summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2005-03-23 20:34:39 +0000
committerMartin Odersky <odersky@gmail.com>2005-03-23 20:34:39 +0000
commitd5dd90881087d6e6940f60a62e1d708670379ff1 (patch)
tree7b66257c0f5914f57e5632a2cb91b6dd7a2a6e51
parent28d2afb09ce1e04fc55a38e5c417bf958fc3fc6d (diff)
downloadscala-d5dd90881087d6e6940f60a62e1d708670379ff1.tar.gz
scala-d5dd90881087d6e6940f60a62e1d708670379ff1.tar.bz2
scala-d5dd90881087d6e6940f60a62e1d708670379ff1.zip
*** empty log message ***
-rwxr-xr-xsources/scala/tools/nsc/symtab/classfile/Constant.scala9
-rwxr-xr-xsources/scala/tools/nsc/symtab/classfile/PickleBuffer.scala118
-rwxr-xr-xsources/scala/tools/nsc/symtab/classfile/PickleFormat.scala91
-rwxr-xr-xsources/scala/tools/nsc/symtab/classfile/Pickler.scala240
-rwxr-xr-xsources/scala/tools/nsc/symtab/classfile/SymblfileParser.scala30
-rwxr-xr-xsources/scala/tools/nsc/symtab/classfile/UnPickler.scala188
-rwxr-xr-xsources/scala/tools/nsc/typechecker/ConstantFolder.scala185
-rw-r--r--sources/scala/tools/nsc/typechecker/EtaExpansion.scala70
-rwxr-xr-xsources/scala/tools/nsc/typechecker/Infer.scala602
-rwxr-xr-xsources/scala/tools/nsc/typechecker/Variances.scala70
-rwxr-xr-xsources/scala/tools/nsc/util/ShowPickled.scala161
11 files changed, 1764 insertions, 0 deletions
diff --git a/sources/scala/tools/nsc/symtab/classfile/Constant.scala b/sources/scala/tools/nsc/symtab/classfile/Constant.scala
new file mode 100755
index 0000000000..32161fdfc1
--- /dev/null
+++ b/sources/scala/tools/nsc/symtab/classfile/Constant.scala
@@ -0,0 +1,9 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.symtab.classfile;
+
+/* A wrapper for constant values */
+case class Constant(value: Any);
diff --git a/sources/scala/tools/nsc/symtab/classfile/PickleBuffer.scala b/sources/scala/tools/nsc/symtab/classfile/PickleBuffer.scala
new file mode 100755
index 0000000000..aed16bf057
--- /dev/null
+++ b/sources/scala/tools/nsc/symtab/classfile/PickleBuffer.scala
@@ -0,0 +1,118 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.symtab.classfile;
+
+/** Variable length byte arrays, with methods for basic pickling and unpickling.
+ * @param data: The initial buffer
+ * @param from: The first index where defined data are found
+ * @param to : The first index where new data can be written
+ */
+class PickleBuffer(data: Array[byte], from: int, to: int) {
+
+ var bytes = data;
+ var readIndex = from;
+ var writeIndex = to;
+
+ /** Double bytes array */
+ private def dble: unit = {
+ val bytes1 = new Array[byte](bytes.length * 2);
+ System.arraycopy(bytes, 0, bytes1, 0, writeIndex);
+ bytes = bytes1
+ }
+
+ def ensureCapacity(capacity: int) = while (bytes.length < writeIndex + capacity) dble;
+
+ // -- Basic output routines --------------------------------------------
+
+ /** Write a byte of data */
+ def writeByte(b: int): unit = {
+ if (writeIndex == bytes.length) dble;
+ bytes(writeIndex) = b.asInstanceOf[byte];
+ writeIndex = writeIndex + 1
+ }
+
+ /** Write a natural number in big endian format, base 128.
+ * All but the last digits have bit 0x80 set.*/
+ def writeNat(x: int): unit = {
+ def writeNatPrefix(x: int): unit = {
+ val y = x >>> 7;
+ if (y != 0) writeNatPrefix(y);
+ writeByte((x & 0x7f) | 0x80);
+ }
+ val y = x >>> 7;
+ if (y != 0) writeNatPrefix(y);
+ writeByte(x & 0x7f)
+ }
+
+ /** Write a natural number at `pos'
+ * If number is more than one byte, shift rest of array to make space. */
+ def patchNat(pos: int, x: int): unit = {
+ def patchNatPrefix(x: int): unit = {
+ writeByte(0);
+ System.arraycopy(bytes, pos, bytes, pos+1, writeIndex - (pos+1));
+ bytes(pos) = ((x & 0x7f) | 0x80).asInstanceOf[byte];
+ val y = x >>> 7;
+ if (y != 0) patchNatPrefix(y)
+ }
+ bytes(pos) = (x & 0x7f).asInstanceOf[byte];
+ val y = x >>> 7;
+ if (y != 0) patchNatPrefix(y);
+ }
+
+ /** Write a long number in signed big endian format, base 256. */
+ def writeLong(x: long): unit = {
+ val y = x >> 8;
+ val z = x & 0xff;
+ if (-y != (z >> 7)) writeLong(y);
+ writeByte(z.asInstanceOf[int]);
+ }
+
+ // -- Basic input routines --------------------------------------------
+
+ /** Read a byte */
+ def readByte(): int = {
+ val x = bytes(readIndex); readIndex = readIndex + 1; x
+ }
+
+ /** Read a natural number in big endian format, base 128.
+ * All but the last digits have bit 0x80 set.*/
+ def readNat(): int = {
+ var b = 0;
+ var x = 0;
+ do {
+ b = readByte();
+ x = (x << 7) + (b & 0x7f);
+ } while ((b & 0x80) != 0);
+ x
+ }
+
+ /** Read a long number in signed big endian format, base 256. */
+ def readLong(len: int): long = {
+ var x = 0L;
+ var i = 0;
+ while (i < len) {
+ x = (x << 8) + (readByte() & 0xff);
+ i = i + 1
+ }
+ val leading = 64 - (len << 3);
+ x << leading >> leading
+ }
+
+ /** Perform operation `op' until readIndex == end. Concatenate results into a list. */
+ def until[T](end: int, op: () => T): List[T] =
+ if (readIndex == end) List() else op() :: until(end, op);
+
+ /** Create an index */
+ def createIndex: Array[int] = {
+ val index = new Array[int](readNat());
+ for (val i <- Iterator.range(0, index.length)) {
+ index(i) = readIndex;
+ readByte();
+ readIndex = readNat() + readIndex
+ }
+ index
+ }
+}
diff --git a/sources/scala/tools/nsc/symtab/classfile/PickleFormat.scala b/sources/scala/tools/nsc/symtab/classfile/PickleFormat.scala
new file mode 100755
index 0000000000..8f1ec5b6ad
--- /dev/null
+++ b/sources/scala/tools/nsc/symtab/classfile/PickleFormat.scala
@@ -0,0 +1,91 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.symtab.classfile;
+
+object PickleFormat {
+
+/***************************************************
+ * Symbol table attribute format:
+ * Symtab = nentries_Nat {Entry}
+ * Entry = 1 TERMNAME len_Nat NameInfo
+ * | 2 TYPENAME len_Nat NameInfo
+ * | 3 NONEsym len_Nat
+ * | 4 TYPEsym len_Nat SymbolInfo
+ * | 5 ALIASsym len_Nat SymbolInfo
+ * | 6 CLASSsym len_Nat SymbolInfo [thistype_Ref]
+ * | 7 MODULEsym len_Nat SymbolInfo
+ * | 8 VALsym len_Nat SymbolInfo
+ * | 9 EXTref len_Nat name_Ref [owner_Ref]
+ * | 10 EXTMODCLASSref len_Nat name_Ref [owner_Ref]
+ * | 11 NOtpe len_Nat
+ * | 12 NOPREFIXtpe len_Nat
+ * | 13 THIStpe len_Nat sym_Ref
+ * | 14 SINGLEtpe len_Nat type_Ref sym_Ref
+ * | 15 CONSTANTtpe len_Nat type_Ref constant_Ref
+ * | 16 TYPEREFtpe len_Nat type_Ref sym_Ref {targ_Ref}
+ * | 17 TYPEBOUNDStpe len_Nat tpe_Ref tpe_Ref
+ * | 18 REFINEDtpe len_Nat classsym_Ref {tpe_Ref}
+ * | 19 CLASSINFOtpe len_Nat classsym_Ref {tpe_Ref}
+ * | 20 METHODtpe len_Nat tpe_Ref {tpe_Ref}
+ * | 21 POLYTtpe len_Nat tpe_Ref {sym_Ref}
+ * | 24 LITERALunit len_Nat
+ * | 25 LITERALboolean len_Nat value_Long
+ * | 26 LITERALbyte len_Nat value_Long
+ * | 27 LITERALshort len_Nat value_Long
+ * | 28 LITERALchar len_Nat value_Long
+ * | 29 LITERALint len_Nat value_Long
+ * | 30 LITERALlong len_Nat value_Long
+ * | 31 LITERALfloat len_Nat value_Long
+ * | 32 LITERALdouble len_Nat value_Long
+ * | 33 LITERALstring len_Nat name_Ref
+ * | 34 LITERALnull len_Nat
+ * | 35 LITERALzero len_Nat
+ * SymbolInfo = name_Ref owner_Ref flags_Nat info_Ref
+ * NameInfo = <character sequence of length len_Nat in Utf8 format>
+ * NumInfo = <len_Nat-byte signed number in big endian format>
+ * Ref = Nat
+ *
+ * len is remaining length after `len'.
+ */
+ val TERMname = 1;
+ val TYPEname = 2;
+ val NONEsym = 3;
+ val TYPEsym = 4;
+ val ALIASsym = 5;
+ val CLASSsym = 6;
+ val MODULEsym = 7;
+ val VALsym = 8;
+ val EXTref = 9;
+ val EXTMODCLASSref = 10;
+ val NOtpe = 11;
+ val NOPREFIXtpe = 12;
+ val THIStpe = 13;
+ val SINGLEtpe = 14;
+ val CONSTANTtpe = 15;
+ val TYPEREFtpe = 16;
+ val TYPEBOUNDStpe = 17;
+ val REFINEDtpe = 18;
+ val CLASSINFOtpe = 19;
+ val METHODtpe = 20;
+ val POLYtpe = 21;
+ val LITERALunit = 24;
+ val LITERALboolean = 25;
+ val LITERALbyte = 26;
+ val LITERALshort = 27;
+ val LITERALchar = 28;
+ val LITERALint = 29;
+ val LITERALlong = 30;
+ val LITERALfloat = 31;
+ val LITERALdouble = 32;
+ val LITERALstring = 33;
+ val LITERALnull = 34;
+ val LITERALzero = 35;
+
+ val firstSymTag = NONEsym;
+ val lastSymTag = VALsym;
+ val firstTypeTag = NOtpe;
+ val lastTypeTag = POLYtpe;
+}
diff --git a/sources/scala/tools/nsc/symtab/classfile/Pickler.scala b/sources/scala/tools/nsc/symtab/classfile/Pickler.scala
new file mode 100755
index 0000000000..c1f2b0d2d4
--- /dev/null
+++ b/sources/scala/tools/nsc/symtab/classfile/Pickler.scala
@@ -0,0 +1,240 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.symtab.classfile;
+
+import java.io._;
+import java.lang.{Float, Double}
+import scala.collection.mutable.HashMap;
+import Flags._;
+import PickleFormat._;
+
+/**
+ * Serialize a top-level module and/or class;
+ * @see EntryTags.scala for symbol table attribute format.
+ */
+abstract class Pickler {
+ val global: Global;
+ import global._;
+
+ class PicklePhase(prev: Phase) extends StdPhase(prev) {
+ def name = "pickler";
+ val global: Pickler.this.global.type = Pickler.this.global;
+ def apply(unit: CompilationUnit): unit = pickle(unit.body);
+
+ private def pickle(tree: Tree): unit = tree match {
+ case PackageDef(_, stats) => stats foreach pickle;
+ case ClassDef(_, _, _, _, _) | ModuleDef(_, _, _) =>
+ val sym = tree.symbol;
+ System.out.println("add " + sym);//debug
+ System.out.println("pickling " + tree + " " + sym);//debug
+ val pickle = new Pickle(sym.name.toTermName, sym.owner);
+ def add(sym: Symbol) = {
+ if (!sym.isExternal && !symData.contains(sym)) {
+ if (settings.debug.value) log("pickling " + sym);
+ pickle.putSymbol(sym);
+ symData(sym) = pickle;
+ }
+ }
+ add(sym);
+ add(sym.linkedSym);
+ pickle.finish
+ case _ =>
+ }
+ }
+
+ class Pickle(rootName: Name, rootOwner: Symbol) extends PickleBuffer(new Array[byte](4096), -1, 0) {
+ private var entries = new Array[AnyRef](256);
+ private var ep = 0;
+ private val index = new HashMap[Any, int];
+
+ /** Is root in symbol.owner*? */
+ private def isLocal(sym: Symbol): boolean =
+ sym.name.toTermName == rootName && sym.owner == rootOwner ||
+ sym != NoSymbol && isLocal(sym.owner);
+
+ // Phase 1 methods: Populate entries/index ------------------------------------
+
+ /** Store entry `e' in index at next available position unless it it
+ * already there. Return true iff entry is new. */
+ private def putEntry(entry: AnyRef): boolean = index.get(entry) match {
+ case Some(_) => false
+ case None =>
+ if (ep == entries.length) {
+ val entries1 = new Array[AnyRef](ep * 2);
+ System.arraycopy(entries, 0, entries1, 0, ep);
+ entries = entries1;
+ }
+ entries(ep) = entry;
+ index(entry) = ep;
+ ep = ep + 1;
+ true
+ }
+
+ /** Store symbol in index. If symbol is local, also store everything it refers to. */
+ def putSymbol(sym: Symbol): unit = if (putEntry(sym)) {
+ System.out.println("put symbol " + sym);
+ if (isLocal(sym)) {
+ putEntry(sym.name);
+ putSymbol(sym.owner);
+ putType(sym.info);
+ if (sym.thisSym != sym) putType(sym.typeOfThis)
+ } else if (sym != NoSymbol) {
+ putEntry(if (sym.isModuleClass) sym.name.toTermName else sym.name);
+ if (!sym.owner.isRoot) putSymbol(sym.owner);
+ }
+ }
+ private def putSymbols(syms: List[Symbol]) = syms foreach putSymbol;
+
+ /** Store type and everythig it refers to in index. */
+ private def putType(tp: Type): unit = if (putEntry(tp)) {
+ tp match {
+ case NoType | NoPrefix =>
+ ;
+ case ThisType(sym) =>
+ putSymbol(sym)
+ case SingleType(pre, sym) =>
+ putType(pre); putSymbol(sym)
+ case ConstantType(base, value) =>
+ putType(base); putConstant(value)
+ case TypeRef(pre, sym, args) =>
+ putType(pre); putSymbol(sym); putTypes(args)
+ case TypeBounds(lo, hi) =>
+ putType(lo); putType(hi);
+ case RefinedType(parents, decls) =>
+ putSymbol(tp.symbol); putTypes(parents); putSymbols(decls.toList)
+ case ClassInfoType(parents, decls, clazz) =>
+ putSymbol(clazz); putTypes(parents); putSymbols(decls.toList)
+ case MethodType(formals, restpe) =>
+ putType(restpe); putTypes(formals)
+ case PolyType(tparams, restpe) =>
+ putType(restpe); putSymbols(tparams)
+ case _ =>
+ throw new FatalError("bad type: " + tp + "(" + tp.getClass() + ")")
+ }
+ }
+ private def putTypes(tps: List[Type]): unit = tps foreach putType;
+
+ private def putConstant(value: Any) = if (putEntry(Constant(value))) {
+ value match {
+ case str: String => putEntry(newTermName(str))
+ case _ =>
+ }
+ }
+
+ // Phase 2 methods: Write all entries to byte array ------------------------------
+
+ private val buf = new PickleBuffer(new Array[byte](4096), -1, 0);
+
+ /** Write a reference to object, i.e., the object's number in the index. */
+ private def writeRef(ref: Any): unit = writeNat(index(ref));
+ private def writeRefs(refs: List[Any]): unit = refs foreach writeRef;
+
+ /** Write name, owner, flags, and info of a symbol */
+ private def writeSymInfo(sym: Symbol): unit = {
+ writeRef(sym.name);
+ writeRef(sym.owner);
+ System.out.println("" + sym + " has flags " + sym.flags + " " + (sym.flags & PickledFlags));
+ writeNat((sym.flags & PickledFlags).asInstanceOf[int]);
+ writeRef(sym.info)
+ }
+
+ /** Write a name in Utf8 format. */
+ def writeName(name: Name): unit = {
+ ensureCapacity(name.length * 3);
+ writeIndex = name.copyUTF8(bytes, writeIndex);
+ }
+
+ /** Write an entry */
+ private def writeEntry(entry: AnyRef): unit = {
+ def writeBody: 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 != sym) writeRef(sym.typeOfThis);
+ CLASSsym
+ case sym: TypeSymbol =>
+ writeSymInfo(sym);
+ if (sym.isAbstractType) TYPEsym else ALIASsym
+ case sym: ModuleSymbol =>
+ writeSymInfo(sym); MODULEsym
+ case sym: TermSymbol =>
+ writeSymInfo(sym); VALsym
+ case NoType =>
+ NOtpe
+ case NoPrefix =>
+ NOPREFIXtpe
+ case ThisType(sym) =>
+ writeRef(sym); THIStpe
+ case SingleType(pre, sym) =>
+ writeRef(pre); writeRef(sym); SINGLEtpe
+ case ConstantType(base, value) =>
+ writeRef(base); 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.symbol); writeRefs(parents); REFINEDtpe
+ case ClassInfoType(parents, decls, clazz) =>
+ writeRef(clazz); writeRefs(parents); CLASSINFOtpe
+ case MethodType(formals, restpe) =>
+ writeRef(restpe); writeRefs(formals); METHODtpe
+ case PolyType(tparams, restpe) =>
+ writeRef(restpe); writeRefs(tparams); POLYtpe
+ case Constant(null) =>
+ LITERALnull
+ case Constant(x: unit) =>
+ LITERALunit
+ case Constant(x: boolean) =>
+ writeLong(if (x) 1 else 0); LITERALboolean
+ case Constant(x: byte) =>
+ writeLong(x); LITERALbyte
+ case Constant(x: char) =>
+ writeLong(x); LITERALchar
+ case Constant(x: short) =>
+ writeLong(x); LITERALshort
+ case Constant(x: int) =>
+ writeLong(x); LITERALint
+ case Constant(x: long) =>
+ writeLong(x); LITERALlong
+ case Constant(x: float) =>
+ writeLong(Float.floatToIntBits(x)); LITERALfloat
+ case Constant(x: double) =>
+ writeLong(Double.doubleToLongBits(x)); LITERALdouble
+ case Constant(x: String) =>
+ writeRef(newTermName(x)); LITERALstring
+ case _ =>
+ throw new FatalError("bad entry: " + entry + " " + entry.getClass());//debug
+ }
+ val startpos = writeIndex;
+ writeByte(0); writeByte(0);
+ patchNat(startpos, writeBody);
+ patchNat(startpos + 1, writeIndex - (startpos + 2));
+ }
+
+ /** Write byte array */
+ def finish = {
+ assert(writeIndex == 0);
+ writeNat(ep);
+ System.out.println("" + ep + " entries");//debug
+ for (val i <- Iterator.range(0, ep)) writeEntry(entries(i))
+ }
+ }
+}
+
diff --git a/sources/scala/tools/nsc/symtab/classfile/SymblfileParser.scala b/sources/scala/tools/nsc/symtab/classfile/SymblfileParser.scala
new file mode 100755
index 0000000000..fd6834260f
--- /dev/null
+++ b/sources/scala/tools/nsc/symtab/classfile/SymblfileParser.scala
@@ -0,0 +1,30 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.symtab.classfile;
+
+import scala.tools.util._;
+import java.io.IOException;
+
+abstract class SymblfileParser {
+
+ val global: Global;
+ import global._;
+
+ private var current: AbstractFile = null; // lock to detect recursive reads
+
+ private object unpickler extends UnPickler {
+ val global: SymblfileParser.this.global.type = SymblfileParser.this.global
+ }
+
+ def parse(file: AbstractFile, root: Symbol): unit = {
+ assert(current == null, current);
+ current = file;
+ val in = new AbstractFileReader(file);
+ if (root.isModule) unpickler.unpickle(in.buf, 0, root.linkedClass, root)
+ else unpickler.unpickle(in.buf, 0, root, root.linkedModule);
+ current = null
+ }
+}
diff --git a/sources/scala/tools/nsc/symtab/classfile/UnPickler.scala b/sources/scala/tools/nsc/symtab/classfile/UnPickler.scala
new file mode 100755
index 0000000000..6012d428c4
--- /dev/null
+++ b/sources/scala/tools/nsc/symtab/classfile/UnPickler.scala
@@ -0,0 +1,188 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.symtab.classfile;
+
+import scala.tools.util.{Position, UTF8Codec};
+import java.lang.{Float, Double};
+import Flags._;
+import PickleFormat._;
+
+abstract class UnPickler {
+ val global: Global;
+ import global._;
+
+ def unpickle(bytes: Array[byte], offset: int, classRoot: Symbol, moduleRoot: Symbol): unit = try {
+ new UnPickle(bytes, offset, classRoot, moduleRoot);
+ } catch {
+ case ex: Throwable =>
+ if (settings.debug.value) ex.printStackTrace();
+ throw new RuntimeException("error readng Scala signature: " + ex.getMessage());
+ }
+
+ private class UnPickle(bytes: Array[byte], offset: int, classRoot: Symbol, moduleRoot: Symbol) extends PickleBuffer(bytes, offset, -1) {
+ if (settings.debug.value) global.log("unpickle " + classRoot + " and " + moduleRoot);
+
+ private val index = createIndex;
+ private val entries = new Array[AnyRef](index.length);
+ for (val i <- Iterator.range(0, index.length))
+ if (isSymbolEntry(i)) { at(i, readSymbol); () }
+
+ if (settings.debug.value) global.log("unpickled " + classRoot + ":" + classRoot.rawInfo + ", " + moduleRoot + ":" + moduleRoot.rawInfo);//debug
+
+ /** Does entry represent an (internal) symbol */
+ private def isSymbolEntry(i: int): boolean = {
+ val tag = bytes(index(i));
+ firstSymTag <= tag && tag <= lastSymTag
+ }
+
+ /** If entry at `i' is undefined, define it by performing operation `op' with
+ * readIndex at start of i'th entry. Restore readIndex afterwards. */
+ private def at[T <: AnyRef](i: int, op: () => T): T = {
+ var r = entries(i);
+ if (r == null) {
+ val savedIndex = readIndex;
+ readIndex = index(i);
+ r = op();
+ assert(entries(i) == null, entries(i));
+ entries(i) = r;
+ readIndex = savedIndex;
+ }
+ r.asInstanceOf[T]
+ }
+
+ /** Read a name */
+ private def readName(): Name = {
+ val tag = readByte();
+ val len = readNat();
+ tag match {
+ case TERMname => newTermName(bytes, readIndex, len)
+ case TYPEname => newTypeName(bytes, readIndex, len)
+ case _ => errorBadSignature("bad name tag: " + tag);
+ }
+ }
+
+ /** Read a symbol */
+ private def readSymbol(): Symbol = {
+ val tag = readByte();
+ val end = readNat() + readIndex;
+ var sym: Symbol = NoSymbol;
+ tag match {
+ case EXTref | EXTMODCLASSref =>
+ val name = readNameRef();
+ val owner = if (readIndex == end) definitions.RootClass else readSymbolRef();
+ sym = if (tag == EXTref) owner.info.decl(name)
+ else if (name.toTermName == nme.ROOT) definitions.RootClass
+ else owner.info.decl(name).moduleClass;
+ if (sym == NoSymbol)
+ errorBadSignature(
+ "reference " + (if (name.isTypeName) "type " else "value ") +
+ name.decode + " of " + owner + " refers to nonexisting symbol.")
+ case NONEsym =>
+ sym = NoSymbol
+ case _ =>
+ val name = readNameRef();
+ System.out.println("reading symbol " + name);//debug
+ val owner = readSymbolRef();
+ val flags = readNat();
+ val inforef = readNat();
+ tag match {
+ case TYPEsym =>
+ sym = owner.newAbstractType(Position.NOPOS, name);
+ case ALIASsym =>
+ sym = owner.newAliasType(Position.NOPOS, name);
+ case CLASSsym =>
+ sym = if ((flags & MODULE) == 0 &&
+ name == classRoot.name && owner == classRoot.owner) classRoot
+ else owner.newClass(Position.NOPOS, name);
+ if (readIndex != end) sym.typeOfThis = new LazyTypeRef(readNat())
+ case MODULEsym =>
+ val mclazz = at(inforef, readType).symbol.asInstanceOf[ClassSymbol];
+ sym = if (name == moduleRoot.name && owner == moduleRoot.owner) moduleRoot
+ else owner.newModule(Position.NOPOS, name, mclazz)
+ case VALsym =>
+ sym = owner.newValue(Position.NOPOS, name)
+ case _ =>
+ errorBadSignature("bad symbol tag: " + tag);
+ }
+ sym.setFlag(flags);
+ sym.setInfo(new LazyTypeRef(inforef));
+ if (sym.owner.isClass && !sym.isModuleClass && !sym.hasFlag(PARAM))
+ sym.owner.info.decls enter sym
+ }
+ sym
+ }
+
+ /** Read a type */
+ private def readType(): Type = {
+ val tag = readByte();
+ val end = readNat() + readIndex;
+ tag match {
+ case NOtpe =>
+ NoType
+ case NOPREFIXtpe =>
+ NoPrefix
+ case THIStpe =>
+ ThisType(readSymbolRef())
+ case SINGLEtpe =>
+ singleType(readTypeRef(), readSymbolRef())
+ case CONSTANTtpe =>
+ ConstantType(readTypeRef(), readConstantRef().value)
+ case TYPEREFtpe =>
+ // create a type-ref as found, without checks or rebinds
+ new TypeRef(readTypeRef(), readSymbolRef(), until(end, readTypeRef)) {}
+ case TYPEBOUNDStpe =>
+ new TypeBounds(readTypeRef(), readTypeRef())
+ case REFINEDtpe =>
+ val clazz = readSymbolRef();
+ new RefinedType(until(end, readTypeRef), new Scope()) { override def symbol = clazz }
+ case CLASSINFOtpe =>
+ val clazz = readSymbolRef();
+ ClassInfoType(until(end, readTypeRef), new Scope(), clazz)
+ case METHODtpe =>
+ val restpe = readTypeRef();
+ MethodType(until(end, readTypeRef), restpe)
+ case POLYtpe =>
+ val restpe = readTypeRef();
+ PolyType(until(end, readSymbolRef), restpe)
+ case _ =>
+ errorBadSignature("bad type tag: " + tag);
+ }
+ }
+
+ /** Read a constant */
+ private def readConstant(): Constant = {
+ val tag = readByte();
+ val len = readNat();
+ tag match {
+ case LITERALunit => Constant(())
+ case LITERALboolean => Constant(if (readLong(len) == 0) false else true)
+ case LITERALbyte => Constant(readLong(len).asInstanceOf[byte])
+ case LITERALshort => Constant(readLong(len).asInstanceOf[short])
+ case LITERALchar => Constant(readLong(len).asInstanceOf[char])
+ case LITERALint => Constant(readLong(len).asInstanceOf[int])
+ case LITERALlong => Constant(readLong(len))
+ case LITERALfloat => Constant(Float.intBitsToFloat(readLong(len).asInstanceOf[int]))
+ case LITERALdouble => Constant(Double.longBitsToDouble(readLong(len)))
+ case LITERALstring => Constant(readNameRef().toString())
+ case LITERALnull => Constant(null)
+ case _ => errorBadSignature("bad constant tag: " + tag)
+ }
+ };
+
+ /** Read a reference to a name, symbol, type or constant */
+ private def readNameRef(): Name = at(readNat(), readName);
+ private def readSymbolRef(): Symbol = at(readNat(), readSymbol);
+ private def readTypeRef(): Type = at(readNat(), readType);
+ private def readConstantRef(): Constant = at(readNat(), readConstant);
+
+ private def errorBadSignature(msg: String) =
+ throw new RuntimeException("malformed Scala signature at " + readIndex + "; " + msg);
+
+ private class LazyTypeRef(i: int) extends LazyType {
+ override def complete(sym: Symbol): unit = sym setInfo at(i, readType)
+ }
+ }
+}
diff --git a/sources/scala/tools/nsc/typechecker/ConstantFolder.scala b/sources/scala/tools/nsc/typechecker/ConstantFolder.scala
new file mode 100755
index 0000000000..3971167d0c
--- /dev/null
+++ b/sources/scala/tools/nsc/typechecker/ConstantFolder.scala
@@ -0,0 +1,185 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.typechecker;
+
+abstract class ConstantFolder {
+
+ val global: Global;
+ import global._;
+ import definitions._;
+
+ private val NoValue = new Object();
+
+ /** If tree is a constant operation, replace with result. */
+ def apply(tree: Tree): Tree = {
+ val newvalue = tree match {
+ case Apply(Select(Literal(x), op), List(Literal(y))) => foldBinop(op, x, y)
+ case Select(Literal(x), op) => foldUnop(op, x)
+ case _ => NoValue
+ }
+ if (newvalue != NoValue) Literal(newvalue) else tree
+ }
+
+ /** If tree is a constant value that can be converted to type `pt', perform the conversion */
+ def apply(tree: Tree, pt: Type): Tree = {
+ val newvalue = tree match {
+ case Literal(value) => foldTyped(value, pt)
+ case _ => NoValue
+ }
+ if (newvalue != NoValue) Literal(newvalue) else tree
+ }
+
+ private def foldUnop(op: Name, value: Any): Any = Pair(op, value) match {
+ case Pair(nme.ZNOT, x: boolean) => !x
+
+ case Pair(nme.NOT , x: int ) => ~x
+ case Pair(nme.NOT , x: long ) => ~x
+
+ case Pair(nme.ADD , x: int ) => +x
+ case Pair(nme.ADD , x: long ) => +x
+ case Pair(nme.ADD , x: float ) => +x
+ case Pair(nme.ADD , x: double ) => +x
+
+ case Pair(nme.SUB , x: int ) => -x
+ case Pair(nme.SUB , x: long ) => -x
+ case Pair(nme.SUB , x: float ) => -x
+ case Pair(nme.SUB , x: double ) => -x
+
+ case _ => NoValue
+ }
+
+ private def foldBinop(op: Name, lvalue: Any, rvalue: Any): Any = Triple(op, lvalue, rvalue) match {
+ case Triple(nme.ZOR , x: boolean, y: boolean) => x | y
+ case Triple(nme.OR, , x: boolean, y: boolean) => x | y
+ case Triple(nme.OR , x: int , y: int ) => x | y
+ case Triple(nme.OR , x: long , y: long ) => x | y
+
+ case Triple(nme.XOR , x: boolean, y: boolean) => x ^ y
+ case Triple(nme.XOR , x: int , y: int ) => x ^ y
+ case Triple(nme.XOR , x: long , y: long ) => x ^ y
+
+ case Triple(nme.ZAND, x: boolean, y: boolean) => x & y
+ case Triple(nme.AND , x: boolean, y: boolean) => x & y
+ case Triple(nme.AND , x: int , y: int ) => x & y
+ case Triple(nme.AND , x: long , y: long ) => x & y
+
+ case Triple(nme.LSL , x: int , y: int ) => x << y
+ case Triple(nme.LSL , x: long , y: int ) => x << y
+ case Triple(nme.LSL , x: long , y: long ) => x << y
+
+ case Triple(nme.LSR , x: int , y: int ) => x >>> y
+ case Triple(nme.LSR , x: long , y: int ) => x >>> y
+ case Triple(nme.LSR , x: long , y: long ) => x >>> y
+
+ case Triple(nme.ASR , x: int , y: int ) => x >> y
+ case Triple(nme.ASR , x: long , y: int ) => x >> y
+ case Triple(nme.ASR , x: long , y: long ) => x >> y
+
+ case Triple(nme.EQ , x: boolean, y: boolean) => x == y
+ case Triple(nme.EQ , x: int , y: int ) => x == y
+ case Triple(nme.EQ , x: long , y: long ) => x == y
+ case Triple(nme.EQ , x: float , y: float ) => x == y
+ case Triple(nme.EQ , x: double , y: double ) => x == y
+
+ case Triple(nme.NE , x: boolean, y: boolean) => x != y
+ case Triple(nme.NE , x: int , y: int ) => x != y
+ case Triple(nme.NE , x: long , y: long ) => x != y
+ case Triple(nme.NE , x: float , y: float ) => x != y
+ case Triple(nme.NE , x: double , y: double ) => x != y
+
+ case Triple(nme.LT , x: int , y: int ) => x < y
+ case Triple(nme.LT , x: long , y: long ) => x < y
+ case Triple(nme.LT , x: float , y: float ) => x < y
+ case Triple(nme.LT , x: double , y: double ) => x < y
+
+ case Triple(nme.GT , x: int , y: int ) => x > y
+ case Triple(nme.GT , x: long , y: long ) => x > y
+ case Triple(nme.GT , x: float , y: float ) => x > y
+ case Triple(nme.GT , x: double , y: double ) => x > y
+
+ case Triple(nme.LE , x: int , y: int ) => x <= y
+ case Triple(nme.LE , x: long , y: long ) => x <= y
+ case Triple(nme.LE , x: float , y: float ) => x <= y
+ case Triple(nme.LE , x: double , y: double ) => x <= y
+
+ case Triple(nme.GE , x: int , y: int ) => x >= y
+ case Triple(nme.GE , x: long , y: long ) => x >= y
+ case Triple(nme.GE , x: float , y: float ) => x >= y
+ case Triple(nme.GE , x: double , y: double ) => x >= y
+
+ case Triple(nme.ADD , x: int , y: int ) => x + y
+ case Triple(nme.ADD , x: long , y: long ) => x + y
+ case Triple(nme.ADD , x: float , y: float ) => x + y
+ case Triple(nme.ADD , x: double , y: double ) => x + y
+ case Triple(nme.ADD , x: String , y: String ) => x + y
+
+ case Triple(nme.SUB , x: int , y: int ) => x - y
+ case Triple(nme.SUB , x: long , y: long ) => x - y
+ case Triple(nme.SUB , x: float , y: float ) => x - y
+ case Triple(nme.SUB , x: double , y: double ) => x - y
+
+ case Triple(nme.MUL , x: int , y: int ) => x * y
+ case Triple(nme.MUL , x: long , y: long ) => x * y
+ case Triple(nme.MUL , x: float , y: float ) => x * y
+ case Triple(nme.MUL , x: double , y: double ) => x * y
+
+ case Triple(nme.DIV , x: int , y: int ) => x / y
+ case Triple(nme.DIV , x: long , y: long ) => x / y
+ case Triple(nme.DIV , x: float , y: float ) => x / y
+ case Triple(nme.DIV , x: double , y: double ) => x / y
+
+ case Triple(nme.MOD , x: int , y: int ) => x % y
+ case Triple(nme.MOD , x: long , y: long ) => x % y
+ case Triple(nme.MOD , x: float , y: float ) => x % y
+ case Triple(nme.MOD , x: double , y: double ) => x % y
+
+ case _ => NoValue
+ }
+
+ /** Widen constant value to conform to given type */
+ private def foldTyped(value: Any, pt: Type): Any = {
+ val target = pt.symbol;
+ value match {
+ case x: byte =>
+ if (target == ShortClass) x.asInstanceOf[short]
+ else if (target == CharClass) x.asInstanceOf[char]
+ else if (target == IntClass) x.asInstanceOf[int]
+ else if (target == LongClass) x.asInstanceOf[long]
+ else if (target == FloatClass) x.asInstanceOf[float]
+ else if (target == DoubleClass) x.asInstanceOf[double]
+ else NoValue
+ case x: short =>
+ if (target == IntClass) x.asInstanceOf[int]
+ else if (target == LongClass) x.asInstanceOf[long]
+ else if (target == FloatClass) x.asInstanceOf[float]
+ else if (target == DoubleClass) x.asInstanceOf[double]
+ else NoValue
+ case x: char =>
+ if (target == IntClass) x.asInstanceOf[int]
+ else if (target == LongClass) x.asInstanceOf[long]
+ else if (target == FloatClass) x.asInstanceOf[float]
+ else if (target == DoubleClass) x.asInstanceOf[double]
+ else NoValue
+ case x: int =>
+ if (target == ByteClass && -128 <= x && x <= 127) x.asInstanceOf[byte]
+ else if (target == ShortClass && -32768 <= x && x <= 32767) x.asInstanceOf[short]
+ else if (target == CharClass && 0 <= x && x <= 65535) x.asInstanceOf[char]
+ else if (target == LongClass) x.asInstanceOf[long]
+ else if (target == FloatClass) x.asInstanceOf[float]
+ else if (target == DoubleClass) x.asInstanceOf[double]
+ else NoValue
+ case x: long =>
+ if (target == FloatClass) x.asInstanceOf[float]
+ else if (target == DoubleClass) x.asInstanceOf[double]
+ else NoValue
+ case x: float =>
+ if (target == DoubleClass) x.asInstanceOf[double]
+ else NoValue
+ case x =>
+ NoValue
+ }
+ }
+}
diff --git a/sources/scala/tools/nsc/typechecker/EtaExpansion.scala b/sources/scala/tools/nsc/typechecker/EtaExpansion.scala
new file mode 100644
index 0000000000..4c8052563c
--- /dev/null
+++ b/sources/scala/tools/nsc/typechecker/EtaExpansion.scala
@@ -0,0 +1,70 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.typechecker;
+
+import collection.mutable.ListBuffer;
+import symtab.Flags._;
+
+class EtaExpansion: Analyzer {
+
+ import global._;
+ import posAssigner.atPos;
+
+ /** Expand partial function applications of type `type'.
+ *
+ * p.f(es_1)...(es_n)
+ * ==> {
+ * private synthetic val eta$f = p.f // if p is not stable
+ * ...
+ * private synthetic val eta$e_i = e_i // if e_i is not stable
+ * ...
+ *
+ * (ps_1 => ... => ps_m => eta$f([es_1])...([es_m])(ps_1)...(ps_m))
+ * }
+ * tree is already attributed
+ */
+ def etaExpand(tree: Tree, tpe: Type): Tree = {
+ var cnt = 0;
+ def freshName() = { cnt = cnt + 1; newTermName("eta$" + cnt) }
+ val defs = new ListBuffer[Tree];
+
+ /** Append to `defs' value definitions for all non-stable subexpressions
+ * of the function application `tree' */
+ def liftoutPrefix(tree: Tree): Tree = {
+ def liftout(tree: Tree): Tree =
+ if (treeInfo.isPureExpr(tree)) tree
+ else {
+ val vname: Name = freshName();
+ defs += ValDef(SYNTHETIC, vname, TypeTree(), tree);
+ Ident(vname)
+ }
+ tree match {
+ case Apply(fn, args) =>
+ copy.Apply(tree, liftoutPrefix(fn), args mapConserve liftout);
+ case TypeApply(fn, args) =>
+ copy.TypeApply(tree, liftoutPrefix(fn), args)
+ case Select(qual, name) =>
+ copy.Select(tree, liftout(qual), name)
+ case Ident(name) =>
+ tree
+ }
+ }
+
+ /** Eta-expand lifted tree */
+ def expand(tree: Tree, tpe: Type): Tree = tpe match {
+ case MethodType(formals, restpe) =>
+ val params = formals map (formal =>
+ ValDef(SYNTHETIC | PARAM, freshName(), TypeTree().setType(formal), EmptyTree));
+ val args = params map (param => Ident(param.name));
+ Function(params, expand(Apply(tree, args), restpe))
+ case _ =>
+ tree
+ }
+
+ val tree1 = liftoutPrefix(tree);
+ atPos(tree.pos)(Block(defs.toList, expand(tree1, tpe)))
+ }
+}
diff --git a/sources/scala/tools/nsc/typechecker/Infer.scala b/sources/scala/tools/nsc/typechecker/Infer.scala
new file mode 100755
index 0000000000..513cb9cc31
--- /dev/null
+++ b/sources/scala/tools/nsc/typechecker/Infer.scala
@@ -0,0 +1,602 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.typechecker;
+
+class Infer: Analyzer {
+ import symtab.Flags._;
+ import global._;
+ import definitions._;
+ import posAssigner.atPos;
+ import scala.collection.mutable.ListBuffer;
+
+/* -- Type parameter inference utility functions -------------------------------------- */
+
+ /** The formal parameter types corresponding to `formals'.
+ * If `formals' has a repeated last parameter, a list of
+ * (nargs - params.length + 1) copies of its type is returned. */
+ def formalTypes(formals: List[Type], nargs: int): List[Type] =
+ if (!formals.isEmpty && (formals.last.symbol == RepeatedParamClass)) {
+ val ft = formals.last.typeArgs.head;
+ formals.init ::: (for (val i <- List.range(formals.length - 1, nargs)) yield ft)
+ } else formals;
+
+ /** A fresh type varable with given type parameter as origin. */
+ def freshVar(tparam: Symbol): TypeVar = new TypeVar(tparam.tpe, new TypeConstraint);
+
+ private class NoInstance(msg: String) extends RuntimeException(msg);
+
+ private class DeferredNoInstance(getmsg: () => String) extends NoInstance("") {
+ override def getMessage(): String = getmsg()
+ }
+
+ private object instantiateMap extends TypeMap {
+ def apply(t: Type): Type = instantiate(t)
+ }
+
+ /** map every TypeVar to its constraint.inst field.
+ * throw a NoInstance exception if a NoType or WildcardType is encountered.
+ * @throws NoInstance
+ */
+ def instantiate(tp: Type): Type = tp match {
+ case WildcardType | NoType =>
+ throw new NoInstance("undetermined type");
+ case TypeVar(origin, constr) =>
+ if (constr.inst != NoType) instantiate(constr.inst)
+ else throw new DeferredNoInstance(() =>
+ "no unique instantiation of type variable " + origin + " could be found");
+ case _ =>
+ instantiateMap.mapOver(tp)
+ }
+
+ /** Is type fully defined, i.e. no embedded anytypes or wildcards in it? */
+ def isFullyDefined(tp: Type): boolean = try {
+ instantiate(tp); true
+ } catch {
+ case ex: NoInstance => false
+ }
+
+ /** Do type arguments `targs' conform to formal parameters `tparams'? */
+ private def isWithinBounds(tparams: List[Symbol], targs: List[Type]): boolean = {
+ val bounds = tparams map (.info.subst(tparams, targs).bounds);
+ List.map2(bounds, targs)((bound, targ) => bound containsType targ) forall (x => x)
+ }
+
+ /** Solve constraint collected in types `tvars'
+ * @param tvars All type variables to be instantiated.
+ * @param tparams The type parameters corresponding to `tvars'
+ * @param variances The variances of type parameters; need to reverse
+ * solution direction for all contravariant variables.
+ * @param upper When `true' search for max solution else min.
+ * @throws NoInstance
+ */
+ private def solve(tvars: List[TypeVar], tparams: List[Symbol], variances: List[int],
+ upper: boolean): List[Type] = {
+ val config = tvars zip (tparams zip variances);
+
+ def solveOne(tvar: TypeVar, tparam: Symbol, variance: int): unit =
+ if (tvar.constr.inst == NoType) {
+ val up = if (variance != CONTRAVARIANT) upper else !upper;
+ tvar.constr.inst = null;
+ val bound: Type = if (up) tparam.info.bounds.hi else tparam.info.bounds.lo;
+ var cyclic = false;
+ for (val Pair(tvar2, Pair(tparam2, variance2)) <- config) {
+ if ((bound contains tparam2) ||
+ up && (tparam2.info.bounds.lo =:= tparam.tpe) ||
+ !up && (tparam2.info.bounds.hi =:= tparam.tpe)) {
+ if (tvar2.constr.inst == null) cyclic = true;
+ solveOne(tvar2, tparam2, variance2);
+ }
+ }
+ if (!cyclic) {
+ if (up) {
+ if (bound.symbol != AnyClass) {
+ tvar.constr.hibounds =
+ bound.subst(tparams, tvars) :: tvar.constr.hibounds;
+ for (val tparam2 <- tparams)
+ if (tparam2.info.bounds.lo =:= tparam.tpe)
+ tvar.constr.hibounds =
+ tparam2.tpe.subst(tparams, tvars) :: tvar.constr.hibounds;
+ }
+ } else {
+ if (bound.symbol != AllClass) {
+ tvar.constr.lobounds =
+ bound.subst(tparams, tvars) :: tvar.constr.lobounds;
+ for (val tparam2 <- tparams)
+ if (tparam2.info.bounds.hi =:= tparam.tpe)
+ tvar.constr.lobounds =
+ tparam2.tpe.subst(tparams, tvars) :: tvar.constr.lobounds;
+ }
+ }
+ tvar.constr.inst = if (up) glb(tvar.constr.hibounds) else lub(tvar.constr.lobounds)
+ }
+ }
+
+ for (val Pair(tvar, Pair(tparam, variance)) <- config) solveOne(tvar, tparam, variance);
+ tvars map instantiate;
+ }
+
+ def skipImplicit(tp: Type) = if (tp.isInstanceOf[ImplicitMethodType]) tp.resultType else tp;
+
+ /** Automatically perform the following conversions on expression types:
+ * A method type becomes the corresponding function type.
+ * A nullary method type becomes its result type.
+ * Implicit parameters are skipped.
+ */
+ private def normalize(tp: Type): Type = skipImplicit(tp) match {
+ case MethodType(formals, restpe) => functionType(formals, normalize(restpe))
+ case PolyType(List(), restpe) => normalize(restpe);
+ case _ => tp
+ }
+
+ class TreeSubstituter(tparams: List[Symbol], targs: List[Type]) extends Traverser {
+ val typeSubst = new SubstTypeMap(tparams, targs);
+ override def traverse(tree: Tree): unit = {
+ if (tree.tpe != null) tree.tpe = typeSubst(tree.tpe);
+ super.traverse(tree)
+ }
+ }
+
+ /** The context-dependent inferencer part */
+ class Inferencer(context: Context) {
+
+ /* -- Error Messages ----------------------------------------------------- */
+
+ def setError[T <: Tree](tree: T): T = {
+ val name = newTermName("<error: " + tree + ">");
+ if (tree.hasSymbol)
+ tree.setSymbol(
+ if (tree.isType) context.owner.newErrorClass(name.toTypeName)
+ else context.owner.newErrorValue(name));
+ tree.setType(ErrorType)
+ }
+
+ def decode(name: Name): String =
+ (if (name.isTypeName) "type " else "value ") + name.decode;
+
+ def treeSymTypeMsg(tree: Tree): String =
+ if (tree.symbol == null)
+ "expression of type " + tree.tpe
+ else if (tree.symbol.hasFlag(OVERLOADED))
+ "overloaded method " + tree.symbol + " with alternatives " + tree.tpe
+ else
+ tree.symbol.toString() +
+ (if (tree.tpe.paramSectionCount > 0) "" else " of type ") +
+ tree.tpe;
+
+ def overloadErrorMsg(pre: Type, sym1: Symbol, sym2: Symbol): String =
+ "ambiguous reference to overloaded definition,\n" +
+ "both " + sym1 + ": " + pre.memberType(sym1) + "\n" +
+ "and " + sym2 + ": " + pre.memberType(sym2) + "\nmatch";
+
+ def applyErrorMsg(tree: Tree, msg: String, argtpes: List[Type], pt: Type) =
+ treeSymTypeMsg(tree) + msg + argtpes.mkString("(", ",", ")") +
+ (if (pt == WildcardType) "" else " with expected result type " + pt);
+
+ def foundReqMsg(found: Type, req: Type): String =
+ ";\n found : " + found.toLongString + "\n required: " + req;
+
+ def error(pos: int, msg: String): unit =
+ context.unit.error(pos, msg);
+
+ def errorTree(tree: Tree, msg: String): Tree = {
+ error(tree.pos, msg);
+ setError(tree)
+ }
+
+ def typeError(pos: int, found: Type, req: Type): unit =
+ if (!found.isError && !req.isError) {
+ error(pos,
+ "type mismatch" + foundReqMsg(found, req) +
+ (if (!(found.resultType eq found) && isCompatible(found.resultType, req))
+ "\n possible cause: missing arguments for method or constructor"
+ else ""));
+ if (settings.explaintypes.value)
+ explainTypes(found, req);
+ }
+
+ def typeErrorTree(tree: Tree, found: Type, req: Type): Tree = {
+ typeError(tree.pos, found, req);
+ setError(tree)
+ }
+
+ /* -- Views --------------------------------------------------------------- */
+
+ def availableViews(argtp: Type): List[Type] = List(); // for now
+ def bestView(argtp: Type, pt: Type): Symbol = NoSymbol; // for now
+ def bestView(argtp: Type, name: Name): Symbol = NoSymbol; // for now
+
+ object inferView extends Inferencer(context) {
+ override def availableViews(argtp: Type): List[Type] = List()
+ }
+
+ /* -- Tests & Checks-------------------------------------------------------- */
+
+ /** Is `sym' accessible as a member of tree `site' with type `pre' in current context?
+ */
+ private def isAccessible(sym: Symbol, pre: Type, site: Tree): boolean = {
+
+ /** Are we inside definition of `owner'? */
+ def accessWithin(owner: Symbol): boolean = {
+ var c = context;
+ while (c != NoContext && c.owner != owner) c = c.outer.enclClass;
+ c != NoContext;
+ }
+
+ /** Is `clazz' a subclass of an enclosing class? */
+ def isSubClassOfEnclosing(clazz: Symbol): boolean = {
+ var c = context;
+ while (c != NoContext && !clazz.isSubClass(c.owner)) c = c.outer.enclClass;
+ c != NoContext;
+ }
+
+ pre == NoPrefix
+ ||
+ (!sym.hasFlag(PRIVATE | PROTECTED))
+ ||
+ accessWithin(sym.owner)
+ ||
+ (!sym.hasFlag(PRIVATE) &&
+ (site.isInstanceOf[Super] ||
+ (pre.widen.symbol.isSubClass(sym.owner) && isSubClassOfEnclosing(pre.widen.symbol))))
+ }
+
+ /** Check that `sym' is defined and accessible as a member of tree `site' with type `pre'
+ * in current context. */
+ def checkAccessible(tree: Tree, sym: Symbol, pre: Type, site: Tree): Tree =
+ if (sym.isError) {
+ tree setSymbol sym setType ErrorType
+ } else if (sym.owner.hasFlag(INCONSTRUCTOR) && !sym.isTypeParameter && site.isInstanceOf[This]) {
+ errorTree(tree, "" + sym + " cannot be accessed from constructor");
+ } else {
+ val sym1 = sym filter (alt => isAccessible(alt, pre, site));
+ if (sym1 == NoSymbol) {
+ errorTree(tree, sym.toString() + " cannot be accessed in " + pre.widen)
+ } else {
+ tree setSymbol sym1 setType pre.memberType(sym1)
+ }
+ }
+
+
+ def isCompatible(tp: Type, pt: Type): boolean = {
+ val tp1 = normalize(tp);
+ (tp1 <:< pt)/* ||
+ (availableViews(tp1) exists (view =>
+ inferView.isApplicable(List(), view.methtpe, List(tp1), pt)))*/
+ }
+
+ def isCompatible(tps: List[Type], pts: List[Type]): boolean =
+ List.map2(tps, pts)((tp, pt) => isCompatible(tp, pt)) forall (x => x);
+
+ /* -- Type instantiation------------------------------------------------------------ */
+
+ /** Return inferred type arguments of polymorphic expression, given
+ * its type parameters and result type and a prototype `pt'.
+ * If no minimal type variables exist that make the
+ * instantiated type a subtype of `pt', return null.
+ */
+ private def exprTypeArgs(tparams: List[Symbol], restpe: Type, pt: Type): List[Type] = {
+ val tvars = tparams map freshVar;
+ if (isCompatible(restpe.subst(tparams, tvars), pt)) {
+ try {
+ solve(tvars, tparams, tparams map varianceInType(restpe), false);
+ } catch {
+ case ex: NoInstance => null
+ }
+ } else null
+ }
+
+ /** Return inferred proto-type arguments of function, given
+ * its type and value parameters and result type, and a
+ * prototype `pt' for the function result.
+ * Type arguments need to be either determined precisely by
+ * the prototype, or they are maximized, if they occur only covariantly
+ * in the value parameter list.
+ * If instantiation of a type parameter fails,
+ * take WildcardType for the proto-type argument. */
+ def protoTypeArgs(tparams: List[Symbol], formals: List[Type], restpe: Type,
+ pt: Type): List[Type] = {
+ /** Map type variable to its instance, or, if `variance' is covariant/contravariant,
+ * to its upper/lower bound; */
+ def instantiateToBound(tvar: TypeVar, variance: int): Type = try {
+ if (tvar.constr.inst != NoType) {
+ instantiate(tvar.constr.inst)
+ } else if ((variance & COVARIANT) != 0 && !tvar.constr.hibounds.isEmpty) {
+ tvar.constr.inst = glb(tvar.constr.hibounds);
+ instantiate(tvar.constr.inst)
+ } else if ((variance & CONTRAVARIANT) != 0 && !tvar.constr.lobounds.isEmpty) {
+ tvar.constr.inst = lub(tvar.constr.lobounds);
+ instantiate(tvar.constr.inst)
+ } else {
+ WildcardType
+ }
+ } catch {
+ case ex: NoInstance => WildcardType
+ }
+ val tvars = tparams map freshVar;
+ if (isCompatible(restpe.subst(tparams, tvars), pt))
+ List.map2(tparams, tvars) ((tparam, tvar) =>
+ instantiateToBound(tvar, varianceInTypes(formals)(tparam)))
+ else
+ tvars map (tvar => WildcardType)
+ }
+
+ /** Return inferred type arguments, given type parameters, formal parameters,
+ * argument types, result type and expected result type.
+ * If this is not possible, throw a `NoInstance' exception.
+ * Undetermined type arguments are represented by `definitions.AllClass.tpe'.
+ * No check that inferred parameters conform to their bounds is made here.
+ * @param tparams the type parameters of the method
+ * @param formals the value parameter types of the method
+ * @param restp the result type of the method
+ * @param argtpes the argument types of the application
+ * @param pt the expected return type of the application
+ * @param uninstantiated a listbuffer receiving all uninstantiated type parameters
+ * (type parameters mapped by the constraint solver to `scala.All'
+ * and not covariant in `restpe' are taken to be uninstantiated.
+ * Maps all those type arguments to their corresponding type
+ * parameters).
+ */
+ private def methTypeArgs(tparams: List[Symbol], formals: List[Type], restpe: Type,
+ argtpes: List[Type], pt: Type,
+ uninstantiated: ListBuffer[Symbol]): List[Type] = {
+ val tvars = tparams map freshVar;
+ if (formals.length != argtpes.length) {
+ throw new NoInstance("parameter lists differ in length");
+ }
+ // check first whether type variables can be fully defined from
+ // expected result type.
+ if (!isCompatible(restpe.subst(tparams, tvars), pt)) {
+ throw new DeferredNoInstance(() =>
+ "result type " + normalize(restpe) + " is incompatible with expected type " + pt)
+ }
+ for (val tvar <- tvars)
+ if (!isFullyDefined(tvar)) tvar.constr.inst = NoType;
+
+ // Then define remaining type variables from argument types.
+ List.map2(argtpes, formals) {(argtpe, formal) =>
+ if (!isCompatible(argtpe.deconst.subst(tparams, tvars),
+ formal.subst(tparams, tvars))) {
+ if (settings.explaintypes.value)
+ explainTypes(argtpe.deconst.subst(tparams, tvars), formal.subst(tparams, tvars));
+ throw new DeferredNoInstance(() =>
+ "argument expression's type is not compatible with formal parameter type" +
+ foundReqMsg(argtpe.deconst.subst(tparams, tvars), formal.subst(tparams, tvars)))
+ }
+ ()
+ }
+ val targs = solve(tvars, tparams, tparams map varianceInTypes(formals), false);
+ List.map2(tparams, targs) ((tparam, targ) =>
+ if (targ.symbol == AllClass && (varianceInType(restpe)(tparam) & COVARIANT) == 0) {
+ uninstantiated += tparam;
+ tparam.tpe
+ } else targ)
+ }
+
+
+ /** Is there an instantiation of free type variables `undetparams' such that
+ * function type `ftpe' is applicable to `argtpes' and its result conform to `pt'? */
+ def isApplicable(undetparams: List[Symbol], ftpe: Type, argtpes: List[Type], pt: Type): boolean =
+ ftpe match {
+ case MethodType(formals0, restpe) =>
+ val formals = formalTypes(formals0, argtpes.length);
+ if (undetparams.isEmpty) {
+ formals.length == argtpes.length &&
+ isCompatible(argtpes, formals) &&
+ isCompatible(restpe, pt)
+ } else {
+ try {
+ val uninstantiated = new ListBuffer[Symbol];
+ val targs = methTypeArgs(undetparams, formals, restpe, argtpes, pt, uninstantiated);
+ isWithinBounds(undetparams, targs) &&
+ exprTypeArgs(uninstantiated.toList, restpe.subst(undetparams, targs), pt) != null
+ } catch {
+ case ex: NoInstance => false
+ }
+ }
+ case PolyType(tparams, restpe) =>
+ val tparams1 = tparams map (.cloneSymbol);
+ isApplicable(tparams1 ::: undetparams, restpe.substSym(tparams, tparams1), argtpes, pt)
+ case ErrorType =>
+ true
+ case _ =>
+ false
+ }
+
+ /** Does type `ftpe1' specialize type `ftpe2'
+ * when both are alternatives in an overloaded function? */
+ def specializes(ftpe1: Type, ftpe2: Type): boolean = ftpe1 match {
+ case MethodType(formals, _) =>
+ isApplicable(List(), ftpe2, formals, WildcardType)
+ case PolyType(tparams, MethodType(formals, _)) =>
+ isApplicable(List(), ftpe2, formals, WildcardType)
+ case ErrorType =>
+ true
+ case _ =>
+ false
+ }
+
+ /** error if arguments not within bounds. */
+ def checkBounds(pos: int, tparams: List[Symbol], targs: List[Type], prefix: String): unit =
+ if (!isWithinBounds(tparams, targs)) {
+ error(pos,
+ prefix + "type arguments " + targs.mkString("[", ",", "]") +
+ " do not conform to " + tparams.head.owner + "'s type parameter bounds " +
+ (tparams map (.defString)).mkString("[", ",", "]"));
+ if (settings.explaintypes.value) {
+ val bounds = tparams map (.info.subst(tparams, targs).bounds);
+ List.map2(targs, bounds)((targ, bound) => explainTypes(bound.lo, targ));
+ List.map2(targs, bounds)((targ, bound) => explainTypes(targ, bound.hi));
+ ()
+ }
+ }
+
+ /** Substitite free type variables `undetparams' of polymorphic argument expression `tree',
+ * given two prototypes `strictPt', and `lenientPt'.
+ * `strictPt' is the first attempt prototype where type parameters
+ * are left unchanged. `lenientPt' is the fall-back prototype where type parameters
+ * are replaced by `AnyType's. We try to instantiate first to `strictPt' and then,
+ * if this fails, to `lenientPt'. If both attempts fail, an error is produced.
+ */
+ def inferArgumentInstance(tree: Tree, undetparams: List[Symbol], strictPt: Type, lenientPt: Type): unit = {
+ var targs = exprTypeArgs(undetparams, tree.tpe, strictPt);
+ if (targs == null) targs = exprTypeArgs(undetparams, tree.tpe, lenientPt);
+ substExpr(tree, undetparams, targs, lenientPt)
+ }
+
+ /** Substitite free type variables `undetparams; of polymorphic expression `tree',
+ * given prototype `pt'. */
+ def inferExprInstance(tree: Tree, undetparams: List[Symbol], pt: Type): unit =
+ substExpr(tree, undetparams, exprTypeArgs(undetparams, tree.tpe, pt), pt);
+
+ /** Substitite free type variables `undetparams' of polymorphic argument expression `tree' to
+ * `targs', Error if `targs' is null */
+ private def substExpr(tree: Tree, undetparams: List[Symbol], targs: List[Type], pt: Type): unit =
+ if (targs == null) {
+ error(tree.pos, "polymorphic expression cannot be instantiated to expected type" +
+ foundReqMsg(PolyType(undetparams, skipImplicit(tree.tpe)), pt));
+ } else {
+ checkBounds(tree.pos, undetparams, targs, "inferred ");
+ new TreeSubstituter(undetparams, targs).traverse(tree);
+ }
+
+ /** Substitite free type variables `undetparams' of application `fn(args)', given prototype `pt'.
+ * Return the list of type parameters that remain uninstantiated. */
+ def inferMethodInstance(fn: Tree, undetparams: List[Symbol], args: List[Tree], pt: Type): List[Symbol] = fn.tpe match {
+ case MethodType(formals, restpe) =>
+ try {
+ val argtpes = args map (.tpe.deconst);
+ val uninstantiated = new ListBuffer[Symbol];
+ val targs = methTypeArgs(
+ undetparams, formalTypes(formals, argtpes.length), restpe, argtpes, pt, uninstantiated);
+ checkBounds(fn.pos, undetparams, targs, "inferred ");
+ val treeSubst = new TreeSubstituter(undetparams, targs);
+ treeSubst.traverse(fn);
+ treeSubst.traverseTrees(args);
+ uninstantiated.toList;
+ } catch {
+ case ex: NoInstance =>
+ errorTree(fn,
+ "no type parameters for " +
+ applyErrorMsg(
+ fn, " exist so that it can be applied to arguments ",
+ args map (.tpe.widen), WildcardType) +
+ "\n --- because ---\n" + ex.getMessage());
+ List()
+ }
+ }
+
+ /** Substitite free type variables `undetparams' of type constructor `tree' in pattern,
+ * given prototype `pt'. */
+ def inferConstructorInstance(tree: Tree, undetparams: List[Symbol], pt: Type): unit = {
+ val tvars = undetparams map freshVar;
+ val restpe = skipImplicit(tree.tpe.resultType);
+ if (restpe.subst(undetparams, tvars) <:< pt)
+ try {
+ val targs = solve(tvars, undetparams, undetparams map varianceInType(restpe), true);
+ checkBounds(tree.pos, undetparams, targs, "inferred ");
+ new TreeSubstituter(undetparams, targs).traverse(tree)
+ } catch {
+ case ex: NoInstance =>
+ errorTree(tree, "constructor of type " + restpe +
+ " can be instantiated in more than one way to expected type " + pt +
+ "\n --- because ---\n" + ex.getMessage());
+ }
+ else
+ errorTree(tree, "constructor cannot be instantiated to expected type" +
+ foundReqMsg(restpe, pt))
+ }
+
+ /* -- Overload Resolution ----------------------------------------------------------- */
+
+ /** Assign `tree' the symbol and type of the alternative which matches
+ * prototype `pt', if it exists.
+ * If several alternatives match `pt', take parameterless one.
+ * Error if no or several such alternatives exist.
+ */
+ def inferExprAlternative(tree: Tree, pt: Type): unit = {
+ val pre = tree.symbol.info.prefix;
+ val alts = tree.symbol.alternatives filter (alt =>
+ isCompatible(pre.memberType(alt), pt));
+ def improves(sym1: Symbol, sym2: Symbol): boolean =
+ sym2 == NoSymbol ||
+ ((sym1.owner isSubClass sym2.owner) &&
+ {val tp1 = pre.memberType(sym1);
+ val tp2 = pre.memberType(sym2);
+ tp2 == ErrorType ||
+ !inferView.isCompatible(tp2, pt) && inferView.isCompatible(tp1, pt) ||
+ (tp2.paramSectionCount > 0) && (tp1.paramSectionCount == 0 || specializes(tp1, tp2))
+ });
+ val best = ((NoSymbol: Symbol) /: alts) ((best, alt) =>
+ if (improves(alt, best)) alt else best);
+ val competing = alts dropWhile (alt => best == alt || improves(best, alt));
+ if (best == NoSymbol) {
+ typeErrorTree(tree, tree.symbol.tpe, pt)
+ } else if (!competing.isEmpty) {
+ errorTree(tree, overloadErrorMsg(pre, best, competing.head) + "expected type " + pt)
+ } else {
+ tree.setSymbol(best).setType(pre.memberType(best))
+ }
+ }
+
+ /** Assign `tree' the type of an alternative which is applicable to `argtpes',
+ * and whose result type is compatible with `pt'.
+ * If several applicable alternatives exist, take the
+ * most specialized one.
+ * If no applicable alternative exists, and pt != WildcardType, try again
+ * with pt = WildcardType.
+ * Otherwise, if there is no best alternative, error.
+ */
+ def inferMethodAlternative(tree: Tree, undetparams: List[Symbol], argtpes: List[Type], pt: Type): unit = {
+ val pre = tree.symbol.info.prefix;
+ val alts = tree.symbol.alternatives filter (alt =>
+ isApplicable(undetparams, pre.memberType(alt), argtpes, pt));
+ def improves(sym1: Symbol, sym2: Symbol) = {
+ sym2 == NoSymbol ||
+ ((sym1.owner isSubClass sym2.owner) &&
+ specializes(pre.memberType(sym1), pre.memberType(sym2)))
+ }
+ val best = ((NoSymbol: Symbol) /: alts) ((best, alt) =>
+ if (improves(alt, best)) alt else best);
+ val competing = alts dropWhile (alt => best == alt || improves(best, alt));
+ if (best == NoSymbol) {
+ if (pt == WildcardType) {
+ errorTree(tree, applyErrorMsg(tree, " cannot be applied to ", argtpes, pt))
+ } else {
+ inferMethodAlternative(tree, undetparams, argtpes, WildcardType)
+ }
+ } else if (!competing.isEmpty) {
+ errorTree(tree,
+ overloadErrorMsg(pre, best, competing.head) +
+ "argument types " + argtpes.mkString("(", ",", ")") +
+ (if (pt == WildcardType) "" else " and expected result type " + pt))
+ } else {
+ tree.setSymbol(best).setType(pre.memberType(best))
+ }
+ }
+
+ /** Assign `tree' the type of unique polymorphic alternative with `nparams'
+ * as the number of type parameters, if it exists.
+ * If several or none such polymorphic alternatives exist, error.
+ */
+ def inferPolyAlternative(tree: Tree, nparams: int): unit = {
+ val pre = tree.symbol.info.prefix;
+ val alts = tree.symbol.alternatives filter (alt =>
+ alt.info.typeParams.length == nparams);
+ if (alts.isEmpty) {
+ errorTree(tree,
+ if (tree.symbol.alternatives exists (alt => alt.info.typeParams.length > 0))
+ "wrong number of type parameters for " + treeSymTypeMsg(tree)
+ else treeSymTypeMsg(tree) + " does not take type parameters")
+ } else if (!alts.tail.isEmpty) {
+ errorTree(tree,
+ overloadErrorMsg(pre, alts.head, alts.tail.head) +
+ " polymorphic function with " + nparams + " parameters")
+ } else {
+ tree.setSymbol(alts.head).setType(pre.memberType(alts.head))
+ }
+ }
+ }
+}
diff --git a/sources/scala/tools/nsc/typechecker/Variances.scala b/sources/scala/tools/nsc/typechecker/Variances.scala
new file mode 100755
index 0000000000..10f40fca54
--- /dev/null
+++ b/sources/scala/tools/nsc/typechecker/Variances.scala
@@ -0,0 +1,70 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.typechecker;
+
+/** Variances form a lattice, 0 <= COVARIANT <= Variances, 0 <= CONTRAVARIANT <= Variances
+ */
+class Variances: Analyzer {
+
+ import global._;
+ import symtab.Flags._;
+
+ /** Flip between covariant and contravariant */
+ private def flip(v: int): int = {
+ if (v == COVARIANT) CONTRAVARIANT;
+ else if (v == CONTRAVARIANT) COVARIANT;
+ else v
+ }
+
+ /** Map everything below Variances to 0 */
+ private def cut(v: int): int =
+ if (v == Variances) v else 0;
+
+ /** Compute variance of type parameter `tparam' in types of all symbols `sym'. */
+ def varianceInSyms(syms: List[Symbol])(tparam: Symbol): int =
+ (Variances /: syms) ((v, sym) => v & varianceInSym(sym)(tparam));
+
+ /** Compute variance of type parameter `tparam' in type of symbol `sym'. */
+ def varianceInSym(sym: Symbol)(tparam: Symbol): int =
+ if (sym.isAliasType) cut(varianceInType(sym.info)(tparam))
+ else varianceInType(sym.info)(tparam);
+
+ /** Compute variance of type parameter `tparam' in all types `tps'. */
+ def varianceInTypes(tps: List[Type])(tparam: Symbol): int =
+ (Variances /: tps) ((v, tp) => v & varianceInType(tp)(tparam));
+
+ /** Compute variance of type parameter `tparam' in all type arguments
+ * `tps' which correspond to formal type parameters `tparams'. */
+ def varianceInArgs(tps: List[Type], tparams: List[Symbol])(tparam: Symbol): int = {
+ var v: int = Variances;
+ for (val Pair(tp, tparam) <- tps zip tparams) {
+ val v1 = varianceInType(tp)(tparam);
+ v = v & (if (tparam.hasFlag(COVARIANT)) v1
+ else if (tparam.hasFlag(CONTRAVARIANT)) flip(v1)
+ else cut(v1))
+ }
+ v
+ }
+
+ /** Compute variance of type parameter `tparam' in type `tp'. */
+ def varianceInType(tp: Type)(tparam: Symbol): int = tp match {
+ case ErrorType | WildcardType | NoType | NoPrefix | ThisType(_) | ConstantType(_, _) =>
+ Variances
+ case SingleType(pre, sym) =>
+ cut(varianceInType(pre)(tparam))
+ case TypeRef(pre, sym, args) =>
+ if (sym == tparam) COVARIANT
+ else varianceInType(pre)(tparam) & varianceInArgs(args, sym.typeParams)(tparam)
+ case TypeBounds(lo, hi) =>
+ flip(varianceInType(lo)(tparam)) & varianceInType(hi)(tparam)
+ case RefinedType(parents, defs) =>
+ varianceInTypes(parents)(tparam) & varianceInSyms(defs.toList)(tparam)
+ case MethodType(formals, restpe) =>
+ flip(varianceInTypes(formals)(tparam)) & varianceInType(restpe)(tparam)
+ case PolyType(tparams, restpe) =>
+ flip(varianceInSyms(tparams)(tparam)) & varianceInType(restpe)(tparam)
+ }
+}
diff --git a/sources/scala/tools/nsc/util/ShowPickled.scala b/sources/scala/tools/nsc/util/ShowPickled.scala
new file mode 100755
index 0000000000..481b7278e4
--- /dev/null
+++ b/sources/scala/tools/nsc/util/ShowPickled.scala
@@ -0,0 +1,161 @@
+package scala.tools.nsc.util;
+
+import symtab.Names;
+import symtab.classfile.{PickleBuffer, PickleFormat};
+import symtab.Flags;
+import java.io._;
+import java.lang.{Integer, Float, Double}
+
+object ShowPickled extends Names {
+
+ import PickleFormat._;
+
+ def tag2string(tag: int): String = tag match {
+ case TERMname => "TERMname";
+ case TYPEname => "TYPEname";
+ case NONEsym => "NONEsym";
+ case TYPEsym => "TYPEsym";
+ case ALIASsym => "ALIASsym";
+ case CLASSsym => "CLASSsym";
+ case MODULEsym => "MODULEsym";
+ case VALsym => "VALsym";
+ case EXTref => "EXTref";
+ case EXTMODCLASSref => "EXTMODCLASSref";
+ case NOtpe => "NOtpe";
+ case NOPREFIXtpe => "NOPREFIXtpe";
+ case THIStpe => "THIStpe";
+ case SINGLEtpe => "SINGLEtpe";
+ case CONSTANTtpe => "CONSTANTtpe";
+ case TYPEREFtpe => "TYPEREFtpe";
+ case TYPEBOUNDStpe => "TYPEBOUNDStpe";
+ case REFINEDtpe => "REFINEDtpe";
+ case CLASSINFOtpe => "CLASSINFOtpe";
+ case CLASSINFOtpe => "CLASSINFOtpe";
+ case METHODtpe => "METHODtpe";
+ case POLYtpe => "POLYtpe";
+ case LITERALunit => "LITERALunit";
+ case LITERALboolean => "LITERALboolean";
+ case LITERALbyte => "LITERALbyte";
+ case LITERALshort => "LITERALshort";
+ case LITERALchar => "LITERALchar";
+ case LITERALint => "LITERALint";
+ case LITERALlong => "LITERALlong";
+ case LITERALfloat => "LITERALfloat";
+ case LITERALdouble => "LITERALdouble";
+ case LITERALstring => "LITERALstring";
+ case LITERALnull => "LITERALnull";
+ case LITERALzero => "LITERALzero";
+ case _ => "***BAD TAG***(" + tag + ")";
+ }
+
+ def printFile(buf: PickleBuffer, out: PrintStream): unit = {
+ val index = buf.createIndex;
+
+ def printNameRef() = {
+ val x = buf.readNat();
+ val savedIndex = buf.readIndex;
+ buf.readIndex = index(x);
+ val tag = buf.readByte();
+ val len = buf.readNat();
+ out.print(" " + x + "(" + newTermName(buf.bytes, buf.readIndex, len) + ")");
+ buf.readIndex = savedIndex
+ }
+
+ def printNat() = out.print(" " + buf.readNat());
+ def printSymbolRef() = printNat();
+ def printTypeRef() = printNat();
+ def printConstantRef() = printNat();
+
+ def printSymInfo() = {
+ printNameRef();
+ printSymbolRef();
+ val flags = buf.readNat();
+ out.print(" " + Integer.toHexString(flags) + "[" + Flags.flagsToString(flags) + "] ");
+ printTypeRef();
+ }
+
+ def printEntry(i: int): unit = {
+ buf.readIndex = index(i);
+ out.print(i + "," + buf.readIndex + ": ");
+ val tag = buf.readByte();
+ out.print(tag2string(tag));
+ val len = buf.readNat();
+ val end = len + buf.readIndex;
+ out.print(" " + len + ":");
+ tag match {
+ case TERMname =>
+ out.print(" ");
+ out.print(newTermName(buf.bytes, buf.readIndex, len).toString());
+ buf.readIndex = end;
+ case TYPEname =>
+ out.print(" ");
+ out.print(newTypeName(buf.bytes, buf.readIndex, len));
+ buf.readIndex = end;
+ case TYPEsym | ALIASsym | CLASSsym | MODULEsym | VALsym =>
+ printSymInfo();
+ if (tag == CLASSsym && (buf.readIndex < end)) printTypeRef();
+ case EXTref | EXTMODCLASSref =>
+ printNameRef();
+ if (buf.readIndex < end) { printSymbolRef() }
+ case THIStpe =>
+ printSymbolRef()
+ case SINGLEtpe =>
+ printTypeRef(); printSymbolRef();
+ case CONSTANTtpe =>
+ printTypeRef(); printConstantRef();
+ case TYPEREFtpe =>
+ printTypeRef(); printSymbolRef(); buf.until(end, printTypeRef)
+ case TYPEBOUNDStpe =>
+ printTypeRef(); printTypeRef();
+ case REFINEDtpe =>
+ printSymbolRef(); buf.until(end, printTypeRef)
+ case CLASSINFOtpe =>
+ printSymbolRef(); buf.until(end, printTypeRef)
+ case METHODtpe =>
+ printTypeRef(); buf.until(end, printTypeRef)
+ case POLYtpe =>
+ printTypeRef(); buf.until(end, printSymbolRef)
+ case LITERALboolean =>
+ out.print(if (buf.readLong(len) == 0) " false" else " true")
+ case LITERALbyte =>
+ out.print(" " + buf.readLong(len).asInstanceOf[byte])
+ case LITERALshort =>
+ out.print(" " + buf.readLong(len).asInstanceOf[short])
+ case LITERALchar =>
+ out.print(" " + buf.readLong(len).asInstanceOf[char])
+ case LITERALint =>
+ out.print(" " + buf.readLong(len).asInstanceOf[int])
+ case LITERALlong =>
+ out.print(" " + buf.readLong(len))
+ case LITERALfloat =>
+ out.print(" " + Float.intBitsToFloat(buf.readLong(len).asInstanceOf[int]))
+ case LITERALdouble =>
+ out.print(" " + Double.longBitsToDouble(buf.readLong(len)))
+ case LITERALstring =>
+ printNameRef();
+ case LITERALnull =>
+ out.print(" <null>")
+ case _ =>
+ }
+ out.println();
+ if (buf.readIndex != end)
+ out.println("BAD ENTRY END: , computed = " + end + ", factual = " + buf.readIndex);
+ }
+
+ for (val i <- Iterator.range(0, index.length))
+ printEntry(i);
+ }
+
+ def main(args: Array[String]): unit = {
+ val file = new File(args(0));
+ try {
+ val stream = new FileInputStream(file);
+ val data = new Array[byte](stream.available());
+ stream.read(data);
+ val pickle = new PickleBuffer(data, 0, data.length);
+ printFile(pickle, System.out);
+ } catch {
+ case ex: IOException => System.out.println("cannot read " + file + ": " + ex.getMessage());
+ }
+ }
+}