summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/symtab
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/symtab')
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Constants.scala191
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala417
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Flags.scala191
-rw-r--r--src/compiler/scala/tools/nsc/symtab/InfoTransformers.scala45
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Names.scala332
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Scopes.scala249
-rw-r--r--src/compiler/scala/tools/nsc/symtab/StdNames.scala356
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala192
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolTable.scala50
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala1055
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala2060
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileConstants.scala42
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala402
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala153
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/PickleBuffer.scala118
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala99
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala244
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/SymblfileParser.scala31
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala260
19 files changed, 6487 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/Constants.scala b/src/compiler/scala/tools/nsc/symtab/Constants.scala
new file mode 100644
index 0000000000..3a6746cf61
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/Constants.scala
@@ -0,0 +1,191 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+// $Id$
+
+package scala.tools.nsc.symtab;
+
+import classfile.PickleFormat._;
+
+[_trait_] abstract class Constants: SymbolTable {
+
+ import definitions._;
+
+ final val UnitTag = LITERALunit - LITERAL;
+ final val BooleanTag = LITERALboolean - LITERAL;
+ final val ByteTag = LITERALbyte - LITERAL;
+ final val ShortTag = LITERALshort - LITERAL;
+ final val CharTag = LITERALchar - LITERAL;
+ final val IntTag = LITERALint - LITERAL;
+ final val LongTag = LITERALlong - LITERAL;
+ final val FloatTag = LITERALfloat - LITERAL;
+ final val DoubleTag = LITERALdouble - LITERAL;
+ final val StringTag = LITERALstring - LITERAL;
+ final val NullTag = LITERALnull - LITERAL;
+ final val ZeroTag = LITERALzero - LITERAL;
+
+ case class Constant(value: Any) {
+ val tag: int =
+ if (value.isInstanceOf[unit]) UnitTag
+ else if (value.isInstanceOf[boolean]) BooleanTag
+ else if (value.isInstanceOf[byte]) ByteTag
+ else if (value.isInstanceOf[short]) ShortTag
+ else if (value.isInstanceOf[char]) CharTag
+ else if (value.isInstanceOf[int]) IntTag
+ else if (value.isInstanceOf[long]) LongTag
+ else if (value.isInstanceOf[float]) FloatTag
+ else if (value.isInstanceOf[double]) DoubleTag
+ else if (value.isInstanceOf[String]) StringTag
+ else if (value == null) NullTag
+ else throw new Error("bad constant value: " + value);
+
+ def tpe: Type = tag match {
+ case UnitTag => UnitClass.tpe
+ case BooleanTag => BooleanClass.tpe
+ case ByteTag => ByteClass.tpe
+ case ShortTag => ShortClass.tpe
+ case CharTag => CharClass.tpe
+ case IntTag => IntClass.tpe
+ case LongTag => LongClass.tpe
+ case FloatTag => FloatClass.tpe
+ case DoubleTag => DoubleClass.tpe
+ case StringTag => StringClass.tpe
+ case NullTag => AllRefClass.tpe
+ }
+
+ /** We need the equals method to take account of tags as well as values */
+ override def equals(other: Any): boolean = other match {
+ case that: Constant => this.value == that.value && this.tag == that.tag
+ case _ => false
+ }
+
+ def booleanValue: boolean =
+ if (tag == BooleanTag) value.asInstanceOf$erased[boolean]
+ else throw new Error("value " + value + " is not a boolean");
+
+ def byteValue: byte = tag match {
+ case ByteTag => value.asInstanceOf$erased[byte]
+ case ShortTag => value.asInstanceOf$erased[short].asInstanceOf[byte]
+ case CharTag => value.asInstanceOf$erased[char].asInstanceOf[byte]
+ case IntTag => value.asInstanceOf$erased[int].asInstanceOf[byte]
+ case LongTag => value.asInstanceOf$erased[long].asInstanceOf[byte]
+ case FloatTag => value.asInstanceOf$erased[float].asInstanceOf[byte]
+ case DoubleTag => value.asInstanceOf$erased[double].asInstanceOf[byte]
+ case _ => throw new Error("value " + value + " is not a byte")
+ }
+
+ def shortValue: short = tag match {
+ case ByteTag => value.asInstanceOf$erased[byte].asInstanceOf[short]
+ case ShortTag => value.asInstanceOf$erased[short]
+ case CharTag => value.asInstanceOf$erased[char].asInstanceOf[short]
+ case IntTag => value.asInstanceOf$erased[int].asInstanceOf[short]
+ case LongTag => value.asInstanceOf$erased[long].asInstanceOf[short]
+ case FloatTag => value.asInstanceOf$erased[float].asInstanceOf[short]
+ case DoubleTag => value.asInstanceOf$erased[double].asInstanceOf[short]
+ case _ => throw new Error("value " + value + " is not a short")
+ }
+
+ def charValue: char = tag match {
+ case ByteTag => value.asInstanceOf$erased[byte].asInstanceOf[char]
+ case ShortTag => value.asInstanceOf$erased[short].asInstanceOf[char]
+ case CharTag => value.asInstanceOf$erased[char]
+ case IntTag => value.asInstanceOf$erased[int].asInstanceOf[char]
+ case LongTag => value.asInstanceOf$erased[long].asInstanceOf[char]
+ case FloatTag => value.asInstanceOf$erased[float].asInstanceOf[char]
+ case DoubleTag => value.asInstanceOf$erased[double].asInstanceOf[char]
+ case _ => throw new Error("value " + value + " is not a char")
+ }
+
+ def intValue: int = tag match {
+ case ByteTag => value.asInstanceOf$erased[byte].asInstanceOf[int]
+ case ShortTag => value.asInstanceOf$erased[short].asInstanceOf[int]
+ case CharTag => value.asInstanceOf$erased[char].asInstanceOf[int]
+ case IntTag => value.asInstanceOf$erased[int]
+ case LongTag => value.asInstanceOf$erased[long].asInstanceOf[int]
+ case FloatTag => value.asInstanceOf$erased[float].asInstanceOf[int]
+ case DoubleTag => value.asInstanceOf$erased[double].asInstanceOf[int]
+ case _ => throw new Error("value " + value + " is not an int")
+ }
+
+ def longValue: long = tag match {
+ case ByteTag => value.asInstanceOf$erased[byte].asInstanceOf[long]
+ case ShortTag => value.asInstanceOf$erased[short].asInstanceOf[long]
+ case CharTag => value.asInstanceOf$erased[char].asInstanceOf[long]
+ case IntTag => value.asInstanceOf$erased[int].asInstanceOf[long]
+ case LongTag => value.asInstanceOf$erased[long]
+ case FloatTag => value.asInstanceOf$erased[float].asInstanceOf[long]
+ case DoubleTag => value.asInstanceOf$erased[double].asInstanceOf[long]
+ case _ => throw new Error("value " + value + " is not a long")
+ }
+
+ def floatValue: float = tag match {
+ case ByteTag => value.asInstanceOf$erased[byte].asInstanceOf[float]
+ case ShortTag => value.asInstanceOf$erased[short].asInstanceOf[float]
+ case CharTag => value.asInstanceOf$erased[char].asInstanceOf[float]
+ case IntTag => value.asInstanceOf$erased[int].asInstanceOf[float]
+ case LongTag => value.asInstanceOf$erased[long].asInstanceOf[float]
+ case FloatTag => value.asInstanceOf$erased[float]
+ case DoubleTag => value.asInstanceOf$erased[double].asInstanceOf[float]
+ case _ => throw new Error("value " + value + " is not a float")
+ }
+/*
+ def doubleValue: double = {
+ System.out.println("doubleValue " + tag + " " + value);
+ tag match {
+ case ByteTag => System.out.println("Byte"); value.asInstanceOf$erased[byte].asInstanceOf[double]
+ case ShortTag => System.out.println("Short"); value.asInstanceOf$erased[short].asInstanceOf[double]
+ case CharTag => System.out.println("Char"); value.asInstanceOf$erased[char].asInstanceOf[double]
+ case IntTag => System.out.println("Int"); value.asInstanceOf$erased[int].asInstanceOf[double]
+ case LongTag => System.out.println("Long"); value.asInstanceOf$erased[long].asInstanceOf[double]
+ case FloatTag => System.out.println("Float"); value.asInstanceOf$erased[float].asInstanceOf[double]
+ case DoubleTag => System.out.println("Double"); value.asInstanceOf$erased[double]
+ case _ => System.out.println("error"); throw new Error("value " + value + " is not a double")
+ }
+ }
+*/
+ def doubleValue: double = tag match {
+ case ByteTag => value.asInstanceOf$erased[byte].asInstanceOf[double]
+ case ShortTag => value.asInstanceOf$erased[short].asInstanceOf[double]
+ case CharTag => value.asInstanceOf$erased[char].asInstanceOf[double]
+ case IntTag => value.asInstanceOf$erased[int].asInstanceOf[double]
+ case LongTag => value.asInstanceOf$erased[long].asInstanceOf[double]
+ case FloatTag => value.asInstanceOf$erased[float].asInstanceOf[double]
+ case DoubleTag => value.asInstanceOf$erased[double]
+ case _ => throw new Error("value " + value + " is not a double")
+ }
+
+ /** Convert constant value to conform to given type */
+ def convertTo(pt: Type): Constant = {
+ val target = pt.symbol;
+ if (target == tpe.symbol)
+ this
+ else if (target == ByteClass && ByteTag <= tag && tag <= IntTag &&
+ -128 <= intValue && intValue <= 127)
+ Constant(byteValue)
+ else if (target == ShortClass && ByteTag <= tag && tag <= IntTag &&
+ -32768 <= intValue && intValue <= 32767)
+ Constant(shortValue)
+ else if (target == CharClass && ByteTag <= tag && tag <= IntTag &&
+ 0 <= intValue && intValue <= 65635)
+ Constant(charValue)
+ else if (target == IntClass && ByteTag <= tag && tag <= IntTag)
+ Constant(intValue)
+ else if (target == LongClass && ByteTag <= tag && tag <= LongTag)
+ Constant(longValue)
+ else if (target == FloatClass && ByteTag <= tag && tag <= FloatTag)
+ Constant(floatValue)
+ else if (target == DoubleClass && ByteTag <= tag && tag <= DoubleTag)
+ Constant(doubleValue)
+ else null
+ }
+
+ def stringValue: String =
+ if (value == null) "null" else value.toString();
+
+ override def hashCode(): int =
+ if (value == null) 0 else value.hashCode() * 41 + 17;
+ }
+
+}
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
new file mode 100644
index 0000000000..36d34f76f1
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -0,0 +1,417 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.symtab;
+
+import scala.tools.nsc.util.Position;
+import collection.mutable.HashMap;
+import Flags._;
+
+[_trait_] abstract class Definitions: SymbolTable {
+
+ object definitions {
+
+ // root packages and classes
+ var RootClass: Symbol = _;
+ var EmptyPackage: Symbol = _;
+ var EmptyPackageClass: Symbol = _;
+ var emptypackagescope: Scope = null; //debug
+
+ var JavaPackage: Symbol = _;
+ var JavaLangPackage: Symbol = _;
+ var ScalaPackage: Symbol = _;
+ var ScalaPackageClass: Symbol = _;
+
+ var AnyClass: Symbol = _;
+ var AnyValClass: Symbol = _;
+ var ObjectClass: Symbol = _;
+
+ var AnyRefClass: Symbol = _;
+
+ var AllRefClass: Symbol = _;
+ var AllClass: Symbol = _;
+
+ var StringClass: Symbol = _;
+ var ThrowableClass: Symbol = _;
+
+ // the scala value classes
+ var UnitClass: Symbol = _;
+ var BooleanClass: Symbol = _;
+ def Boolean_not = getMember(BooleanClass, nme.ZNOT);
+ def Boolean_and = getMember(BooleanClass, nme.ZAND);
+ def Boolean_or = getMember(BooleanClass, nme.ZOR);
+ var ByteClass: Symbol = _;
+ var ShortClass: Symbol = _;
+ var CharClass: Symbol = _;
+ var IntClass: Symbol = _;
+ var LongClass: Symbol = _;
+ var FloatClass: Symbol = _;
+ var DoubleClass: Symbol = _;
+
+ // the scala reference classes
+ var ScalaObjectClass: Symbol = _;
+ def ScalaObjectClass_tag = getMember(ScalaObjectClass, nme.tag );
+ var AttributeClass: Symbol = _;
+ var RefClass: Symbol = _;
+ var TypedCodeClass: Symbol = _;
+ var PartialFunctionClass: Symbol = _;
+ var IterableClass: Symbol = _;
+ def Iterable_next = getMember(IterableClass, "next");
+ def Iterable_hasNext = getMember(IterableClass, "hasNext");
+ var IteratorClass: Symbol = _;
+ var SeqClass: Symbol = _;
+ def Seq_length = getMember(SeqClass, "length");
+ var ListClass: Symbol = _;
+ def List_isEmpty = getMember(ListClass, "isEmpty");
+ def List_head = getMember(ListClass, "head");
+ def List_tail = getMember(ListClass, "tail");
+ var ArrayClass: Symbol = _;
+ var TypeClass: Symbol = _;
+ var SerializableClass: Symbol = _;
+ var PredefModule: Symbol = _;
+ var ConsoleModule: Symbol = _;
+ var MatchErrorClass: Symbol = _;
+ var MatchErrorModule: Symbol = _;
+ def MatchError_fail = getMember(MatchErrorModule, "fail");
+ def MatchError_report = getMember(MatchErrorModule, "report");
+ var ScalaRunTimeModule: Symbol = _;
+ def SeqFactory = getMember(ScalaRunTimeModule, "Seq");
+ var RepeatedParamClass: Symbol = _;
+ var ByNameParamClass: Symbol = _;
+ var TraitClass: Symbol = _;
+
+ val MaxTupleArity = 9;
+ val MaxFunctionArity = 9;
+ var TupleClass: Array[Symbol] = _;
+ def tupleField(n:int, j:int) = getMember(TupleClass(n), "_" + j);
+ var FunctionClass: Array[Symbol] = _;
+ def functionApply(n:int) = getMember(FunctionClass(n), "apply");
+
+ def tupleType(elems: List[Type]) =
+ if (elems.length <= MaxTupleArity) {
+ val sym = TupleClass(elems.length);
+ typeRef(sym.typeConstructor.prefix, sym, elems)
+ } else NoType;
+
+
+ def functionType(formals: List[Type], restpe: Type) =
+ if (formals.length <= MaxFunctionArity) {
+ val sym = FunctionClass(formals.length);
+ typeRef(sym.typeConstructor.prefix, sym, formals ::: List(restpe))
+ } else NoType;
+
+
+ def isTupleType(tp: Type): boolean = tp match {
+ case TypeRef(_, sym, elems) =>
+ elems.length <= MaxTupleArity && sym == TupleClass(elems.length);
+ case _ =>
+ false
+ }
+
+ def isFunctionType(tp: Type): boolean = tp match {
+ case TypeRef(_, sym, args) =>
+ ((args.length > 0) && (args.length - 1 <= MaxFunctionArity) &&
+ (sym == FunctionClass(args.length - 1)))
+ case _ =>
+ false
+ }
+
+ def seqType(arg: Type) =
+ typeRef(SeqClass.typeConstructor.prefix, SeqClass, List(arg));
+
+ def NilModule: Symbol = getModule("scala.Nil");
+ def ConsClass: Symbol = getClass("scala.$colon$colon");
+
+ // members of class scala.Any
+ var Any_== : Symbol = _;
+ var Any_!= : Symbol = _;
+ var Any_equals : Symbol = _;
+ var Any_hashCode : Symbol = _;
+ var Any_toString : Symbol = _;
+ var Any_isInstanceOf: Symbol = _;
+ var Any_asInstanceOf: Symbol = _;
+ var Any_isInstanceOfErased: Symbol = _;
+ var Any_asInstanceOfErased: Symbol = _;
+
+ // members of class java.lang.{Object, String}
+ var Object_eq : Symbol = _;
+ var Object_ne : Symbol = _;
+ var Object_== : Symbol = _;
+ var Object_!= : Symbol = _;
+ var Object_synchronized: Symbol = _;
+ var Object_isInstanceOf: Symbol = _;
+ var Object_asInstanceOf: Symbol = _;
+ def Object_equals = getMember(ObjectClass, nme.equals_);
+ def Object_hashCode = getMember(ObjectClass, nme.hashCode_);
+ def Object_toString = getMember(ObjectClass, nme.toString_);
+
+ var String_+ : Symbol = _;
+
+ // members of class scala.Iterator
+ var Iterator_next : Symbol = _;
+ var Iterator_hasNext : Symbol = _;
+
+ // pattern wildcard
+ var PatternWildcard: Symbol = _;
+
+ // boxed classes
+ var BoxedArrayClass: Symbol = _;
+ var BoxedAnyArrayClass: Symbol = _;
+ var BoxedObjectArrayClass: Symbol = _;
+ var BoxedNumberClass: Symbol = _;
+ var BoxedUnitClass: Symbol = _;
+ var BoxedUnitModule: Symbol = _;
+ def BoxedUnit_UNIT = getMember(BoxedUnitModule, "UNIT");
+ var ObjectRefClass: Symbol = _;
+
+ // special attributes
+ var SerializableAttr: Type = _;
+
+
+ def getModule(fullname: Name): Symbol =
+ getModuleOrClass(fullname, true);
+
+ def getClass(fullname: Name): Symbol =
+ getModuleOrClass(fullname, false);
+
+ def getMember(owner: Symbol, name: Name) = {
+ val result = owner.info.nonPrivateMember(name);
+ if (result == NoSymbol)
+ throw new FatalError(owner.toString() + " does not have a member " + name);
+ result
+ }
+
+ private def getModuleOrClass(fullname: Name, module: boolean): Symbol = {
+ var sym = RootClass;
+ var i = 0;
+ var j = fullname.pos('.', i);
+ while (j < fullname.length) {
+ sym = sym.info.nonPrivateMember(fullname.subName(i, j));
+ i = j + 1;
+ j = fullname.pos('.', i)
+ }
+ val result =
+ if (module) sym.info.nonPrivateMember(fullname.subName(i, j)).suchThat(.hasFlag(MODULE));
+ else sym.info.nonPrivateMember(fullname.subName(i, j).toTypeName);
+ if (result == NoSymbol)
+ throw new FatalError((if (module) "object " else "class ") + fullname + " not found.");
+ result
+ }
+
+ private def newClass(owner: Symbol, name: Name, parents: List[Type]): Symbol = {
+ val clazz = owner.newClass(Position.NOPOS, name.toTypeName);
+ clazz.setInfo(ClassInfoType(parents, new Scope(), clazz));
+ owner.info.decls.enter(clazz);
+ clazz
+ }
+
+ private def newCovariantPolyClass(owner: Symbol, name: Name, parent: Symbol => Type): Symbol = {
+ val clazz = newClass(owner, name, List());
+ val tparam = newTypeParam(clazz, 0) setFlag COVARIANT;
+ clazz.setInfo(
+ PolyType(
+ List(tparam),
+ ClassInfoType(List(parent(tparam)), new Scope(), clazz)))
+ }
+
+ private def newAlias(owner: Symbol, name: Name, alias: Type): Symbol = {
+ val tpsym = owner.newAliasType(Position.NOPOS, name.toTypeName);
+ tpsym.setInfo(alias);
+ owner.info.decls.enter(tpsym);
+ tpsym
+ }
+
+ private def newMethod(owner: Symbol, name: Name): Symbol = {
+ val msym = owner.newMethod(Position.NOPOS, name.encode);
+ owner.info.decls.enter(msym);
+ msym
+ }
+
+ private def newMethod(owner: Symbol, name: Name, formals: List[Type], restpe: Type): Symbol =
+ newMethod(owner, name).setInfo(MethodType(formals, restpe));
+
+ private def newPolyMethod(owner: Symbol, name: Name, tcon: Symbol => Type): Symbol = {
+ val msym = newMethod(owner, name);
+ val tparam = newTypeParam(msym, 0);
+ msym.setInfo(PolyType(List(tparam), tcon(tparam)))
+ }
+
+ private def newTypeParam(owner: Symbol, index: int): Symbol =
+ owner.newTypeParameter(Position.NOPOS, "T" + index)
+ .setInfo(TypeBounds(AllClass.typeConstructor, AnyClass.typeConstructor));
+
+ val boxedClass = new HashMap[Symbol, Symbol];
+ val boxedArrayClass = new HashMap[Symbol, Symbol];
+ val refClass = new HashMap[Symbol, Symbol];
+ private val abbrvTag = new HashMap[Symbol, char];
+
+ private def getValueClass(name: String, tag: char): Symbol = {
+ val result = getClass("scala." + name);
+ boxedClass(result) = getClass("scala.runtime.Boxed" + name);
+ if (name != "Unit") {
+ boxedArrayClass(result) = getClass("scala.runtime.Boxed" + name + "Array");
+ refClass(result) = getClass("scala.runtime." + name + "Ref");
+ }
+ abbrvTag(result) = tag;
+ result
+ }
+
+ /** Is symbol a value class? */
+ def isValueClass(sym: Symbol): boolean = boxedClass contains sym;
+
+ /** Is symbol a value class? */
+ def isNumericValueClass(sym: Symbol): boolean =
+ isValueClass(sym) && sym != BooleanClass && sym != UnitClass;
+
+ /** Is symbol a value or array class? */
+ def isUnboxedClass(sym: Symbol): boolean = isValueClass(sym) || sym == ArrayClass;
+
+ def signature(tp: Type): String = {
+ def flatNameString(sym: Symbol, separator: char): String =
+ if (sym.owner.isPackageClass) sym.fullNameString('.')
+ else flatNameString(sym.owner, separator) + "$" + sym.simpleName;
+ def signature1(tp: Type): String = {
+ if (tp.symbol == ArrayClass) "[" + signature1(tp.typeArgs.head);
+ else if (isValueClass(tp.symbol)) String.valueOf(abbrvTag(tp.symbol))
+ else "L" + flatNameString(tp.symbol, '/') + ";"
+ }
+ if (tp.symbol == ArrayClass) signature1(tp);
+ else flatNameString(tp.symbol, '.')
+ }
+
+ private var isInitialized = false;
+
+ def init: unit = {
+ if (isInitialized) return;
+ isInitialized = true;
+ RootClass =
+ NoSymbol.newClass(Position.NOPOS, nme.ROOT.toTypeName)
+ .setFlag(FINAL | MODULE | PACKAGE | JAVA).setInfo(rootLoader);
+
+ EmptyPackage =
+ RootClass.newPackage(Position.NOPOS, nme.EMPTY_PACKAGE_NAME).setFlag(FINAL);
+ EmptyPackageClass = EmptyPackage.moduleClass;
+ EmptyPackageClass.setInfo(ClassInfoType(List(), new Scope(), EmptyPackageClass));
+
+ EmptyPackage.setInfo(EmptyPackageClass.tpe);
+ RootClass.info.decls.enter(EmptyPackage);
+
+ JavaPackage = getModule("java");
+ JavaLangPackage = getModule("java.lang");
+ ScalaPackage = getModule("scala");
+ ScalaPackageClass = ScalaPackage.tpe.symbol;
+
+ AnyClass = newClass(ScalaPackageClass, "Any", List());
+ AnyValClass = getClass("scala.AnyVal") setFlag SEALED;
+ ObjectClass = getClass("java.lang.Object");
+
+ AnyRefClass = newAlias(ScalaPackageClass, "AnyRef", ObjectClass.typeConstructor);
+
+ AllRefClass = newClass(ScalaPackageClass, "AllRef", List(AnyRefClass.typeConstructor))
+ .setFlag(ABSTRACT | TRAIT | FINAL);
+
+ AllClass = newClass(ScalaPackageClass, "All", List(AnyClass.typeConstructor))
+ .setFlag(ABSTRACT | TRAIT | FINAL);
+
+ StringClass = getClass("java.lang.String");
+ ThrowableClass = getClass("java.lang.Throwable");
+
+ // the scala value classes
+ UnitClass = getValueClass("Unit", 'V');
+ BooleanClass = getValueClass("Boolean", 'Z');
+ ByteClass = getValueClass("Byte", 'B');
+ ShortClass = getValueClass("Short", 'S');
+ CharClass = getValueClass("Char", 'C');
+ IntClass = getValueClass("Int", 'I');
+ LongClass = getValueClass("Long", 'L');
+ FloatClass = getValueClass("Float", 'F');
+ DoubleClass = getValueClass("Double", 'D');
+
+ // the scala reference classes
+ ScalaObjectClass = getClass("scala.ScalaObject");
+ AttributeClass = getClass("scala.Attribute");
+ RefClass = getClass("scala.Ref");
+ TypedCodeClass = getClass("scala.reflect.TypedCode");
+ PartialFunctionClass = getClass("scala.PartialFunction");
+ IterableClass = getClass("scala.Iterable");
+ IteratorClass = getClass("scala.Iterator");
+ SeqClass = getClass("scala.Seq");
+ ListClass = getClass("scala.List");
+ ArrayClass = getClass("scala.Array");
+ TypeClass = getClass("scala.Type");
+ SerializableClass = getClass("java.io.Serializable");
+ PredefModule = getModule("scala.Predef");
+ ConsoleModule = getModule("scala.Console");
+ MatchErrorClass = getClass("scala.MatchError");
+ MatchErrorModule = getModule("scala.MatchError");
+ ScalaRunTimeModule = getModule("scala.runtime.ScalaRunTime");
+ RepeatedParamClass = newCovariantPolyClass(
+ ScalaPackageClass, nme.REPEATED_PARAM_CLASS_NAME,
+ tparam => typeRef(SeqClass.typeConstructor.prefix, SeqClass, List(tparam.typeConstructor)));
+ ByNameParamClass = newCovariantPolyClass(
+ ScalaPackageClass, nme.BYNAME_PARAM_CLASS_NAME, tparam => AnyClass.typeConstructor);
+ TraitClass = getClass("scala._trait_");
+ TupleClass = new Array(MaxTupleArity + 1);
+ for (val i <- List.range(1, MaxTupleArity + 1))
+ TupleClass(i) = getClass("scala.Tuple" + i);
+ FunctionClass = new Array(MaxFunctionArity + 1);
+ for (val i <- List.range(0, MaxFunctionArity + 1))
+ FunctionClass(i) = getClass("scala.Function" + i);
+
+ // members of class scala.Any
+ Any_== = newMethod(
+ AnyClass, "==", List(AnyClass.typeConstructor), BooleanClass.typeConstructor) setFlag FINAL;
+ Any_!= = newMethod(
+ AnyClass, "!=", List(AnyClass.typeConstructor), BooleanClass.typeConstructor) setFlag FINAL;
+ Any_equals = newMethod(
+ AnyClass, "equals", List(AnyClass.typeConstructor), BooleanClass.typeConstructor);
+ Any_hashCode = newMethod(
+ AnyClass, "hashCode", List(), IntClass.typeConstructor);
+ Any_toString = newMethod(
+ AnyClass, "toString", List(), StringClass.typeConstructor);
+
+ Any_isInstanceOf = newPolyMethod(
+ AnyClass, "isInstanceOf", tparam => BooleanClass.typeConstructor) setFlag FINAL;
+ Any_asInstanceOf = newPolyMethod(
+ AnyClass, "asInstanceOf", tparam => tparam.typeConstructor) setFlag FINAL;
+ Any_isInstanceOfErased = newPolyMethod(
+ AnyClass, "isInstanceOf$erased", tparam => BooleanClass.typeConstructor) setFlag FINAL;
+ Any_asInstanceOfErased = newPolyMethod(
+ AnyClass, "asInstanceOf$erased", tparam => tparam.typeConstructor) setFlag FINAL;
+
+ // members of class java.lang.{Object, String}
+ Object_== = newMethod(
+ ObjectClass, "==", List(AnyRefClass.typeConstructor), BooleanClass.typeConstructor) setFlag FINAL;
+ Object_!= = newMethod(
+ ObjectClass, "!=", List(AnyRefClass.typeConstructor), BooleanClass.typeConstructor) setFlag FINAL;
+ Object_eq = newMethod(
+ ObjectClass, "eq", List(AnyRefClass.typeConstructor), BooleanClass.typeConstructor) setFlag FINAL;
+ Object_ne = newMethod(
+ ObjectClass, "ne", List(AnyRefClass.typeConstructor), BooleanClass.typeConstructor) setFlag FINAL;
+ Object_synchronized = newPolyMethod(
+ ObjectClass, "synchronized", tparam => MethodType(List(tparam.typeConstructor), tparam.typeConstructor)) setFlag FINAL;
+ Object_isInstanceOf = newPolyMethod(
+ ObjectClass, "$isInstanceOf",
+ tparam => MethodType(List(), BooleanClass.typeConstructor)) setFlag FINAL;
+ Object_asInstanceOf = newPolyMethod(
+ ObjectClass, "$asInstanceOf",
+ tparam => MethodType(List(), tparam.typeConstructor)) setFlag FINAL;
+ String_+ = newMethod(
+ StringClass, "+", List(AnyClass.typeConstructor), StringClass.typeConstructor) setFlag FINAL;
+
+ PatternWildcard = NoSymbol.newValue(Position.NOPOS, "_").setInfo(AllClass.typeConstructor);
+
+ BoxedArrayClass = getClass("scala.runtime.BoxedArray");
+ BoxedAnyArrayClass = getClass("scala.runtime.BoxedAnyArray");
+ BoxedObjectArrayClass = getClass("scala.runtime.BoxedObjectArray");
+ BoxedNumberClass = getClass("scala.runtime.BoxedNumber");
+ BoxedUnitClass = getClass("scala.runtime.BoxedUnit");
+ BoxedUnitModule = getModule("scala.runtime.BoxedUnit");
+ ObjectRefClass = getClass("scala.runtime.ObjectRef");
+
+ SerializableAttr = getClass("scala.serializable").tpe;
+ }
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/symtab/Flags.scala b/src/compiler/scala/tools/nsc/symtab/Flags.scala
new file mode 100644
index 0000000000..2627640d2e
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/Flags.scala
@@ -0,0 +1,191 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.symtab;
+
+object Flags {
+
+ // modifiers
+ final val IMPLICIT = 0x00000001;
+ final val FINAL = 0x00000002;
+ final val PRIVATE = 0x00000004;
+ final val PROTECTED = 0x00000008;
+
+ final val SEALED = 0x00000010;
+ final val OVERRIDE = 0x00000020;
+ final val CASE = 0x00000040;
+ final val ABSTRACT = 0x00000080; // abstract class, or used in conjunction
+ // with abstract override.
+ // Note difference to DEFERRED!
+
+ final val DEFERRED = 0x00000100; // was `abstract' for members
+ final val METHOD = 0x00000200; // a method
+ final val MODULE = 0x00000400; // symbol is module or class implementing a module
+ final val INTERFACE = 0x00000800; // symbol is an interface
+
+ final val MUTABLE = 0x00001000; // symbol is a mutable variable.
+ final val PARAM = 0x00002000; // symbol is a (value or type) parameter to a method
+ final val PACKAGE = 0x00004000; // symbol is a java package
+ final val DEPRECATED = 0x00008000; // symbol is deprecated.
+
+ final val COVARIANT = 0x00010000; // symbol is a covariant type variable
+ final val CONTRAVARIANT = 0x00020000; // symbol is a contravariant type variable
+ final val ABSOVERRIDE = 0x00040000; // combination of abstract & override
+ final val LOCAL = 0x00080000; // symbol is local to current class.
+ // pre: PRIVATE is also set
+
+ final val JAVA = 0x00100000; // symbol was defined by a Java class
+ final val SYNTHETIC = 0x00200000; // symbol is compiler-generated
+ final val STABLE = 0x00400000; // functions that are assumed to be stable
+ // (typically, access methods for valdefs)
+ final val STATIC = 0x00800000; // static field, method or class
+
+ final val CASEACCESSOR = 0x01000000; // symbol is a case parameter (or its accessor)
+ final val TRAIT = 0x02000000; // symbol is a trait
+ final val BRIDGE = 0x04000000; // function is a bridge method. Set by Erasure
+ final val ACCESSOR = 0x08000000; // a value or variable accessor
+
+ final val SUPERACCESSOR = 0x10000000; // a super accessor
+ final val PARAMACCESSOR = 0x20000000; // for value definitions: is an access method for a final val parameter
+ // for parameters: is a val parameter
+
+ final val CAPTURED = 0x40000000; // variable is accessed from nested function. Set by LambdaLift
+ final val BYNAMEPARAM = 0x40000000; // parameter is by name
+
+ final val LABEL = 0x80000000L; // method symbol is a label. Set by TailCall
+ final val INCONSTRUCTOR = 0x80000000L; // class symbol is defined in this/superclass constructor.
+
+ final val IS_ERROR = 0x100000000L; // symbol is an error symbol
+ final val OVERLOADED = 0x200000000L; // symbol is overloaded
+ final val LIFTED = 0x400000000L; // class has been lifted out to package level
+ // local value has been lifted out to class level
+ //todo: make LIFTED = latePRIVATE?
+
+ final val MIXEDIN = 0x800000000L; // member has been mixed in
+
+ final val EXPANDEDNAME = 0x1000000000L; // name has been expanded with class suffix
+ final val IMPLCLASS = 0x2000000000L; // symbol is an implementation class
+ final val TRANS_FLAG = 0x4000000000L; // transient flag guaranteed to be reset after each phase.
+
+ final val LOCKED = 0x8000000000L; // temporary flag to catch cyclic dependencies
+
+ final val InitialFlags = 0x000000FFFFFFFFFFL; // flags that are enabled from phase 1.
+ final val LateFlags = 0x000FFF0000000000L; // flags that override flags in 0xFFF.
+ final val AntiFlags = 0x7FF0000000000000L; // flags that cancel flags in 0x7FF
+ final val LateShift = 40L;
+ final val AntiShift = 52L;
+
+ // late flags (set by a transformer phase)
+ final val latePRIVATE = (PRIVATE: long) << LateShift;
+ final val lateDEFERRED = (DEFERRED: long) << LateShift;
+ final val lateINTERFACE = (INTERFACE: long) << LateShift;
+ final val lateMODULE = (MODULE: long) << LateShift;
+ final val lateFINAL = (FINAL: long) << LateShift;
+ final val lateMETHOD = (METHOD: long) << LateShift;
+ final val notPRIVATE = (PRIVATE: long) << AntiShift;
+ final val notPROTECTED = (PROTECTED: long) << AntiShift;
+ final val notABSTRACT = (ABSTRACT: long) << AntiShift;
+ final val notOVERRIDE = (OVERRIDE: long) << AntiShift;
+ final val notMETHOD = (METHOD: long) << AntiShift;
+
+ final val STATICMODULE = lateMODULE;
+ final val STATICMEMBER = notOVERRIDE;
+
+
+ // masks
+ /** This flags can be set when class or module symbol is first created. */
+ final val TopLevelCreationFlags =
+ MODULE | PACKAGE | FINAL | JAVA;
+
+ final val ExplicitFlags = // these modifiers can be set explicitly in source programs.
+ PRIVATE | PROTECTED | ABSTRACT | FINAL | SEALED | OVERRIDE | CASE | IMPLICIT | ABSOVERRIDE;
+
+ final val PrintableFlags = // these modifiers appear in TreePrinter output.
+ (ExplicitFlags | LOCAL | SYNTHETIC | STABLE | CASEACCESSOR | ACCESSOR |
+ SUPERACCESSOR | PARAMACCESSOR | BRIDGE | STATIC);
+
+ final val FieldFlags = MUTABLE | CASEACCESSOR | PARAMACCESSOR | STATIC | FINAL;
+
+ final val AccessFlags = PRIVATE | PROTECTED;
+ final val VARIANCES = COVARIANT | CONTRAVARIANT;
+ final val ConstrFlags = JAVA;
+ final val PickledFlags = 0xFFFFFFFF;
+
+ /** Module flags inherited by their module-class */
+ final val ModuleToClassFlags = AccessFlags | PACKAGE | CASE;
+
+ def flagsToString(flags: long, suffixes: List[Pair[long, String]]): String =
+ (for (val i <- List.range(0, 63)) yield {
+ var s = flagToString(flags & (1L << i));
+ suffixes.find(._1.==(i)) match {
+ case Some(Pair(i, suffix)) => s = s + "[" + suffix + "]"
+ case None =>
+ }
+ s
+ }).filter("" !=).mkString("", " ", "");
+
+ def flagsToString(flags: long): String = flagsToString(flags, List());
+
+ private def flagToString(flag: long): String = {
+ if (flag == LABEL) "<label>"
+ else if (flag == INTERFACE) "<interface>"
+ else if (flag == IS_ERROR) "<is-error>"
+ else if (flag == OVERLOADED) "<overloaded>"
+ else if (flag == LIFTED) "<lifted>"
+ else if (flag == TRANS_FLAG) "<trans-flag>"
+ else if (flag == MIXEDIN) "<mixedin>"
+ else if (flag == EXPANDEDNAME) "<expandedname>"
+ else if (flag == LOCKED) "<locked>"
+ else if (flag == STATICMODULE) "<staticobject>"
+ else if (flag == STATICMEMBER) "<staticmember>"
+ else flag.asInstanceOf[int] match {
+ case IMPLICIT => "implicit"
+ case FINAL => "final"
+ case PRIVATE => "private"
+ case PROTECTED => "protected"
+
+ case SEALED => "sealed"
+ case OVERRIDE => "override"
+ case CASE => "case"
+ case ABSTRACT => "abstract"
+
+ case DEFERRED => "<deferred>"
+ case METHOD => "<method>"
+ case TRAIT => "<trait>"
+ case MODULE => "<module>"
+
+ case MUTABLE => "<mutable>"
+ case PARAM => "<param>"
+ case PACKAGE => "<package>"
+ case DEPRECATED => "<deprecated>"
+
+ case COVARIANT => "<covariant>"
+ case CONTRAVARIANT => "<contravariant>"
+ case ABSOVERRIDE => "abstract override"
+ case LOCAL => "<local>"
+
+ case JAVA => "<java>"
+ case SYNTHETIC => "<synthetic>"
+ case STABLE => "<stable>"
+ case STATIC => "<static>"
+
+ case CASEACCESSOR => "<caseaccessor>"
+ case ACCESSOR => "<accessor>"
+
+ case SUPERACCESSOR => "<superaccessor>"
+ case PARAMACCESSOR => "<paramaccessor>"
+ case BRIDGE => "<bridge>"
+ case CAPTURED => "<captured>"
+
+ case _ => ""
+ }
+ }
+ class Flag(mods : int) {
+ def isPrivate = ((mods & PRIVATE ) != 0);
+ def isProtected = ((mods & PROTECTED) != 0);
+ def isVariable = ((mods & MUTABLE) != 0);
+ def isPublic = !isPrivate && !isProtected;
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/symtab/InfoTransformers.scala b/src/compiler/scala/tools/nsc/symtab/InfoTransformers.scala
new file mode 100644
index 0000000000..e1ff9bbac5
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/InfoTransformers.scala
@@ -0,0 +1,45 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.symtab;
+
+[_trait_] abstract class InfoTransformers: SymbolTable {
+
+ abstract class InfoTransformer {
+ var prev: InfoTransformer = this;
+ var next: InfoTransformer = this;
+
+ val pid: Phase#Id;
+ val changesBaseClasses: boolean;
+ def transform(sym: Symbol, tpe: Type): Type;
+
+ def insert(that: InfoTransformer): unit = {
+ assert(this.pid != that.pid);
+ if (that.pid < this.pid) {
+ prev insert that
+ } else if (next.pid <= that.pid && next.pid != NoPhase.id) {
+ next insert that
+ } else {
+ that.next = next;
+ that.prev = this;
+ next.prev = that;
+ this.next = that
+ }
+ }
+
+ def nextFrom(from: Phase#Id): InfoTransformer =
+ if (from == this.pid) this
+ else if (from < this.pid)
+ if (prev.pid < from) this
+ else prev.nextFrom(from);
+ else if (next.pid == NoPhase.id) next
+ else next.nextFrom(from);
+ }
+}
+
+
+
+
+
diff --git a/src/compiler/scala/tools/nsc/symtab/Names.scala b/src/compiler/scala/tools/nsc/symtab/Names.scala
new file mode 100644
index 0000000000..5fedb67ce4
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/Names.scala
@@ -0,0 +1,332 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.symtab;
+
+import scala.tools.util.UTF8Codec;
+import scala.tools.nsc.util.NameTransformer;
+
+class Names {
+
+// Operations -------------------------------------------------------------
+
+ private val HASH_SIZE = 0x8000;
+ private val HASH_MASK = 0x7FFF;
+ private val NAME_SIZE = 0x20000;
+
+ final val nameDebug = false;
+
+ /** memory to store all names sequentially
+ */
+ var chrs: Array[char] = new Array[char](NAME_SIZE);
+ private var nc = 0;
+
+ /** hashtable for finding term names quickly
+ */
+ private val termHashtable = new Array[Name](HASH_SIZE);
+
+ /** hashtable for finding type names quickly
+ */
+ private val typeHashtable = new Array[Name](HASH_SIZE);
+
+ /** the hashcode of a name
+ */
+ private def hashValue(cs: Array[char], offset: int, len: int): int =
+ if (len > 0)
+ (len * (41 * 41 * 41) +
+ cs(offset) * (41 * 41) +
+ cs(offset + len - 1) * 41 +
+ cs(offset + (len >> 1)))
+ else 0;
+
+ /** is (the ascii representation of) name at given index equal to
+ * cs[offset..offset+len-1]?
+ */
+ private def equals(index: int, cs: Array[char], offset: int, len: int): boolean = {
+ var i = 0;
+ while ((i < len) && (chrs(index + i) == cs(offset + i)))
+ i = i + 1;
+ i == len
+ }
+
+ /** enter characters into chrs array
+ */
+ private def enterChars(cs: Array[char], offset: int, len: int): unit = {
+ var i = 0;
+ while (i < len) {
+ if (nc + i == chrs.length) {
+ val newchrs = new Array[char](chrs.length * 2);
+ System.arraycopy(chrs, 0, newchrs, 0, chrs.length);
+ chrs = newchrs;
+ }
+ chrs(nc + i) = cs(offset + i);
+ i = i + 1
+ }
+ if (len == 0) nc = nc + 1
+ else nc = nc + len
+ }
+
+ /** create a term name from the characters in cs[offset..offset+len-1].
+ */
+ def newTermName(cs: Array[char], offset: int, len: int): Name = {
+ val h = hashValue(cs, offset, len) & HASH_MASK;
+ var n = termHashtable(h);
+ while ((n != null) && (n.length != len || !equals(n.start, cs, offset, len))) {
+ n = n.next;
+ }
+ if (n == null) {
+ n = new TermName(nc, len, h);
+ enterChars(cs, offset, len);
+ }
+ n
+ }
+
+ /** create a term name from string
+ */
+ def newTermName(s: String): Name =
+ newTermName(s.toCharArray(), 0, s.length());
+
+ /** create a term name from the UTF8 encoded bytes in bs[offset..offset+len-1].
+ */
+ def newTermName(bs: Array[byte], offset: int, len: int): Name = {
+ val cs = new Array[char](bs.length);
+ val nchrs = UTF8Codec.decode(bs, offset, cs, 0, len);
+ newTermName(cs, 0, nchrs)
+ }
+
+ /** create a type name from the characters in cs[offset..offset+len-1].
+ */
+ def newTypeName(cs: Array[char], offset: int, len: int): Name =
+ newTermName(cs, offset, len).toTypeName;
+
+ /** create a type name from string
+ */
+ def newTypeName(s: String): Name =
+ newTermName(s).toTypeName;
+
+ /** create a type name from the UTF8 encoded bytes in bs[offset..offset+len-1].
+ */
+ def newTypeName(bs: Array[byte], offset: int, len: int): Name =
+ newTermName(bs, offset, len).toTypeName;
+
+
+ def nameChars: Array[char] = chrs;
+
+ implicit def view(s: String): Name = newTermName(s);
+
+// Classes ----------------------------------------------------------------------
+
+ /** The name class */
+ abstract class Name(index: int, len: int) extends Function1[int, char] {
+
+ /** Index into name table */
+ def start: int = index;
+
+ /** next name in the same hash bucket
+ */
+ var next: Name = null;
+
+ /** return the length of this name
+ */
+ final def length: int = len;
+
+ final def isEmpty = length == 0;
+
+ def isTermName: boolean;
+ def isTypeName: boolean;
+ def toTermName: Name;
+ def toTypeName: Name;
+
+
+ /** copy bytes of this name to buffer cs, starting at offset
+ */
+ final def copyChars(cs: Array[char], offset: int) =
+ System.arraycopy(chrs, index, cs, offset, len);
+
+ /** return the ascii representation of this name
+ */
+ final def toChars = {
+ val cs = new Array[char](len);
+ copyChars(cs, 0);
+ cs
+ }
+
+ /** return the string representation of this name
+ */
+ final override def toString(): String = new String(chrs, index, len);
+
+ /** Write to UTF8 representation of this name to given character array.
+ * Start copying to index `to'. Return index of next free byte in array.
+ * Array must have enough remaining space for all bytes
+ * (i.e. maximally 3*length bytes).
+ */
+ final def copyUTF8(bs: Array[byte], offset: int): int =
+ UTF8Codec.encode(chrs, index, bs, offset, len);
+
+ /** return the hash value of this name
+ */
+ final override def hashCode(): int = index;
+
+ /** return the i'th char of this name
+ */
+ final def apply(i: int): char = chrs(index + i);
+
+ /** return the index of first occurrence of char c in this name, length if not found */
+ final def pos(c: char): int = pos(c, 0);
+
+ /** return the index of first occurrence of char c in this name, length if not found */
+ final def pos(s: String): int = pos(s, 0);
+
+ /** return the index of first occurrence of char c in this name from `start',
+ * length if not found */
+ final def pos(c: char, start: int): int = {
+ var i = start;
+ while (i < len && chrs(index + i) != c) i = i + 1;
+ i
+ }
+
+ /** return the index of first occurrence of nonempty string s in this name from `start',
+ * length if not found */
+ final def pos(s: String, start: int): int = {
+ var i = pos(s.charAt(0), start);
+ while (i + s.length() <= len) {
+ var j = 1;
+ while (s.charAt(j) == chrs(index + i + j)) {
+ j = j + 1;
+ if (j == s.length()) return i;
+ }
+ i = pos(s.charAt(0), i + 1)
+ }
+ len
+ }
+
+ /** return the index of last occurrence of char c in this name, -1 if not found.
+ */
+ final def lastPos(c: char): int = lastPos(c, len - 1);
+
+ final def lastPos(s: String): int = lastPos(s, len - s.length());
+
+ /** return the index of last occurrence of char c in this name from `start',
+ * -1 if not found
+ */
+ final def lastPos(c: char, start: int): int = {
+ var i = start;
+ while (i >= 0 && chrs(index + i) != c) i = i - 1;
+ i
+ }
+
+ /** return the index of last occurrence of string s in this name from `start',
+ * -1 if not found
+ */
+ final def lastPos(s: String, start: int): int = {
+ var i = lastPos(s.charAt(0), start);
+ while (i >= 0) {
+ var j = 1;
+ while (s.charAt(j) == chrs(index + i + j)) {
+ j = j + 1;
+ if (j == s.length()) return i;
+ }
+ i = lastPos(s.charAt(0), i - 1)
+ }
+ -s.length()
+ }
+
+ /** does this name start with prefix?
+ */
+ final def startsWith(prefix: Name): boolean = startsWith(prefix, 0);
+
+ /** does this name start with prefix at given start index?
+ */
+ final def startsWith(prefix: Name, start: int): boolean = {
+ var i = 0;
+ while (i < prefix.length && start + i < len && chrs(index + start + i) == chrs(prefix.start + i))
+ i = i + 1;
+ i == prefix.length
+ }
+
+ /** does this name end with suffix?
+ */
+ final def endsWith(suffix: Name): boolean = endsWith(suffix, len);
+
+ /** does this name end with suffix just before given end index?
+ */
+ final def endsWith(suffix: Name, end: int): boolean = {
+ var i = 1;
+ while (i <= suffix.length && i <= end && chrs(index + end - i) == chrs(suffix.start + suffix.length - i))
+ i = i + 1;
+ i > suffix.length
+ }
+
+ /** the subname with characters from start to end-1
+ */
+ def subName(from: int, to: int): Name;
+
+ /** replace all occurrences of `from' by `to' in name.
+ * result is always a term name.
+ */
+ def replace(from: char, to: char): Name = {
+ val cs = new Array[char](len);
+ var i = 0;
+ while (i < len) {
+ val ch = this(i);
+ cs(i) = if (ch == from) to else ch;
+ i = i + 1
+ }
+ newTermName(cs, 0, len)
+ }
+
+ /** Replace operator symbols by corresponding "$op_name" */
+ def encode: Name = {
+ val str = toString();
+ val res = NameTransformer.encode(str);
+ if (res == str) this
+ else if (isTypeName) newTypeName(res)
+ else newTermName(res)
+ }
+
+ /** Replace $op_name by corresponding operator symbol */
+ def decode: String = (
+ NameTransformer.decode(toString()) +
+ (if (nameDebug && isTypeName) "!" else ""));//debug
+ }
+
+ private class TermName(index: int, len: int, hash: int) extends Name(index, len) {
+ next = termHashtable(hash);
+ termHashtable(hash) = this;
+ def isTermName: boolean = true;
+ def isTypeName: boolean = false;
+ def toTermName: Name = this;
+ def toTypeName = {
+ val h = hashValue(chrs, index, len) & HASH_MASK;
+ var n = typeHashtable(h);
+ while (n != null && n.start != index)
+ n = n.next;
+ if (n == null)
+ n = new TypeName(index, len, h);
+ n
+ }
+ def subName(from: int, to: int): Name =
+ newTermName(chrs, start + from, to - from);
+ }
+
+ private class TypeName(index: int, len: int, hash: int) extends Name(index, len) {
+ next = typeHashtable(hash);
+ typeHashtable(hash) = this;
+ def isTermName: boolean = false;
+ def isTypeName: boolean = true;
+ def toTermName: Name = {
+ val h = hashValue(chrs, index, len) & HASH_MASK;
+ var n = termHashtable(h);
+ while (n != null && n.start != index)
+ n = n.next;
+ if (n == null)
+ n = new TermName(index, len, h);
+ n
+ }
+ def toTypeName: Name = this;
+ def subName(from: int, to: int): Name =
+ newTypeName(chrs, start + from, to - from);
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/symtab/Scopes.scala b/src/compiler/scala/tools/nsc/symtab/Scopes.scala
new file mode 100644
index 0000000000..fe8ffaa47b
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/Scopes.scala
@@ -0,0 +1,249 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.symtab;
+
+[_trait_] abstract class Scopes: SymbolTable {
+
+ class ScopeEntry(val sym: Symbol, val owner: Scope) {
+
+ /** the next entry in the hash bucket
+ */
+ var tail: ScopeEntry = _;
+
+ /** the next entry in this scope
+ */
+ var next: ScopeEntry = null;
+
+ override def hashCode(): int = sym.name.start;
+ override def toString(): String = sym.toString();
+ }
+
+ def newScopeEntry(sym: Symbol, owner: Scope): ScopeEntry = {
+ val e = new ScopeEntry(sym, owner);
+ e.next = owner.elems;
+ owner.elems = e;
+ e
+ }
+
+ object NoScopeEntry extends ScopeEntry(NoSymbol, null);
+
+ class Scope(initElems: ScopeEntry) {
+
+ var elems: ScopeEntry = initElems;
+
+ /** The number of times this scope is neted in another
+ */
+ private var nestinglevel = 0;
+
+ /** the hash table
+ */
+ private var hashtable: Array[ScopeEntry] = null;
+
+ /** a cache for all elements, to be used by symbol iterator.
+ */
+ private var elemsCache: List[Symbol] = null;
+
+ /** size and mask of hash tables
+ * todo: make hashtables grow?
+ */
+ private val HASHSIZE = 0x80;
+ private val HASHMASK = 0x7f;
+
+ /** the threshold number of entries from which a hashtable is constructed.
+ */
+ private val MIN_HASH = 8;
+
+ if (size >= MIN_HASH) createHash;
+
+ def this() = this(null: ScopeEntry);
+
+ def this(base: Scope) = {
+ this(base.elems);
+/*
+ if (base.hashtable != null) {
+ this.hashtable = new Array[ScopeEntry](HASHSIZE);
+ System.arraycopy(base.hashtable, 0, this.hashtable, 0, HASHSIZE);
+ }
+*/
+ nestinglevel = base.nestinglevel + 1
+ }
+
+ def this(decls: List[Symbol]) = {
+ this();
+ decls foreach enter
+ }
+
+ /** Returns a new scope with the same content as this one. */
+ def cloneScope: Scope = {
+ val clone = new Scope();
+ this.toList foreach clone.enter;
+ clone
+ }
+
+ /** is the scope empty? */
+ def isEmpty: boolean = elems == null;
+
+ /** the number of entries in this scope */
+ def size: int = {
+ var s = 0;
+ var e = elems;
+ while (e != null) {
+ s = s + 1;
+ e = e.next
+ }
+ s
+ }
+
+ /** enter a scope entry
+ */
+ def enter(e: ScopeEntry): unit = {
+ elemsCache = null;
+ if (hashtable != null) {
+ val i = e.sym.name.start & HASHMASK;
+ elems.tail = hashtable(i);
+ hashtable(i) = elems;
+ } else if (size >= MIN_HASH) {
+ createHash;
+ }
+ }
+
+ /** enter a symbol
+ */
+ def enter(sym: Symbol): unit = enter(newScopeEntry(sym, this));
+
+ /** enter a symbol, asserting that no symbol with same name exists in scope
+ */
+ def enterUnique(sym: Symbol): unit = {
+ assert(lookup(sym.name) == NoSymbol);
+ enter(sym);
+ }
+
+ private def createHash: unit = {
+ hashtable = new Array[ScopeEntry](HASHSIZE);
+ enterInHash(elems);
+ }
+
+ private def enterInHash(e: ScopeEntry): unit = {
+ if (e != null) {
+ enterInHash(e.next);
+ val i = e.sym.name.start & HASHMASK;
+ e.tail = hashtable(i);
+ hashtable(i) = e;
+ }
+ }
+
+ /** remove entry
+ */
+ def unlink(e: ScopeEntry): unit = {
+ if (elems == e) {
+ elems = e.next;
+ } else {
+ var e1 = elems;
+ while (e1.next != e) e1 = e1.next;
+ e1.next = e.next;
+ }
+ if (hashtable != null) {
+ var e1 = hashtable(e.sym.name.start & HASHMASK);
+ if (e1 == e) {
+ hashtable(e.sym.name.start & HASHMASK) = e.tail;
+ } else {
+ while (e1.tail != e) e1 = e1.tail;
+ e1.tail = e.tail;
+ }
+ }
+ elemsCache = null
+ }
+
+ /** remove symbol */
+ def unlink(sym: Symbol): unit = {
+ var e = lookupEntry(sym.name);
+ while (e != null) {
+ if (e.sym == sym) unlink(e);
+ e = lookupNextEntry(e)
+ }
+ }
+
+ /** lookup a symbol
+ */
+ def lookup(name: Name): Symbol = {
+ val e = lookupEntry(name);
+ if (e == null) NoSymbol else e.sym;
+ }
+
+ /** lookup a symbol entry matching given name
+ */
+ def lookupEntry(name: Name): ScopeEntry = {
+ var e: ScopeEntry = null;
+ if (false & hashtable != null) {
+ e = hashtable(name.start & HASHMASK);
+ while (e != null && e.sym.name != name) e = e.tail;
+ } else {
+ e = elems;
+ while (e != null && e.sym.name != name) e = e.next;
+ }
+ e
+ }
+
+ /** lookup next entry with same name as this one */
+ def lookupNextEntry(entry: ScopeEntry): ScopeEntry = {
+ var e = entry;
+ if (hashtable != null) //debug
+ do { e = e.tail } while (e != null && e.sym.name != entry.sym.name)
+ else
+ do { e = e.next } while (e != null && e.sym.name != entry.sym.name);
+ e
+ }
+
+ /** Return all symbols as a list in the order they were entered in this scope.
+ */
+ def toList: List[Symbol] = {
+ if (elemsCache == null) {
+ elemsCache = Nil;
+ var e = elems;
+ while (e != null && e.owner == this) {
+ elemsCache = e.sym :: elemsCache;
+ e = e.next
+ }
+ }
+ elemsCache
+ }
+
+ /** Return all symbols as an interator in the order they were entered in this scope.
+ */
+ def elements: Iterator[Symbol] = toList.elements;
+
+ def mkString(start: String, sep: String, end: String) =
+ toList.map(.defString).mkString(start, sep, end);
+
+ override def toString(): String = mkString("{\n ", ";\n ", "\n}");
+
+ /** Return the nesting level of this scope, i.e. the number of times this scope
+ * was nested in another */
+ def nestingLevel = nestinglevel;
+ }
+
+ /** The empty scope (immutable).
+ */
+ object EmptyScope extends Scope {
+ override def enter(e: ScopeEntry): unit =
+ throw new Error("EmptyScope.enter");
+ }
+
+ /** The error scope.
+ */
+ class ErrorScope(owner: Symbol) extends Scope(null: ScopeEntry) {
+ override def lookupEntry(name: Name): ScopeEntry = {
+ val e = super.lookupEntry(name);
+ if (e != NoSymbol) e
+ else {
+ enter(if (name.isTermName) owner.newErrorValue(name)
+ else owner.newErrorClass(name));
+ super.lookupEntry(name);
+ }
+ }
+ }
+}
+
diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
new file mode 100644
index 0000000000..2b8b8692f5
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
@@ -0,0 +1,356 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.symtab;
+
+import scala.tools.nsc.util.NameTransformer;
+
+[_trait_] abstract class StdNames: SymbolTable {
+
+ object nme {
+
+ // Scala keywords; enter them first to minimize scanner.maxKey
+ val ABSTRACTkw = newTermName("abstract");
+ val CASEkw = newTermName("case");
+ val CLASSkw = newTermName("class");
+ val CATCHkw = newTermName("catch");
+ val DEFkw = newTermName("def");
+ val DOkw = newTermName("do");
+ val ELSEkw = newTermName("else");
+ val EXTENDSkw = newTermName("extends");
+ val FALSEkw = newTermName("false");
+ val FINALkw = newTermName("final");
+ val FINALLYkw = newTermName("finally");
+ val FORkw = newTermName("for");
+ val IFkw = newTermName("if");
+ val IMPLICITkw = newTermName("implicit");
+ val IMPORTkw = newTermName("import");
+ val MATCHkw = newTermName("match");
+ val NEWkw = newTermName("new");
+ val NULLkw = newTermName("null");
+ val OBJECTkw = newTermName("object");
+ val OUTER = newTermName("$outer");
+ val OVERRIDEkw = newTermName("override");
+ val PACKAGEkw = newTermName("package");
+ val PRIVATEkw = newTermName("private");
+ val PROTECTEDkw = newTermName("protected");
+ val RETURNkw = newTermName("return");
+ val REQUIRESkw = newTermName("requires");
+ val SEALEDkw = newTermName("sealed");
+ val SUPERkw = newTermName("super");
+ val THISkw = newTermName("this");
+ val THROWkw = newTermName("throw");
+ val TRAITkw = newTermName("trait");
+ val TRUEkw = newTermName("true");
+ val TRYkw = newTermName("try");
+ val TYPEkw = newTermName("type");
+ val VALkw = newTermName("val");
+ val VARkw = newTermName("var");
+ val WITHkw = newTermName("with");
+ val WHILEkw = newTermName("while");
+ val YIELDkw = newTermName("yield");
+ val DOTkw = newTermName(".");
+ val USCOREkw = newTermName("_");
+ val COLONkw = newTermName(":");
+ val EQUALSkw = newTermName("=");
+ val ARROWkw = newTermName("=>");
+ val LARROWkw = newTermName("<-");
+ val SUBTYPEkw = newTermName("<:");
+ val VIEWBOUNDkw = newTermName("<%");
+ val SUPERTYPEkw = newTermName(">:");
+ val HASHkw = newTermName("#");
+ val ATkw = newTermName("@");
+
+ val LOCALDUMMY_PREFIX_STRING = "local$";
+ val SUPER_PREFIX_STRING = "super$";
+ val EXPAND_SEPARATOR_STRING = "$$";
+ val TUPLE_FIELD_PREFIX_STRING = "_";
+
+ def LOCAL(clazz: Symbol) = newTermName(LOCALDUMMY_PREFIX_STRING + clazz.name);
+ def TUPLE_FIELD(index: int) = newTermName(TUPLE_FIELD_PREFIX_STRING + index);
+
+ val LOCAL_SUFFIX = newTermName(" ");
+ val SETTER_SUFFIX = encode("_=");
+ val IMPL_CLASS_SUFFIX = newTermName("$class");
+ val MODULE_SUFFIX = newTermName("$module");
+ val LOCALDUMMY_PREFIX = newTermName(LOCALDUMMY_PREFIX_STRING);
+ val THIS_SUFFIX = newTermName(".this");
+
+ def isLocalName(name: Name) = name.endsWith(LOCAL_SUFFIX);
+ def isSetterName(name: Name) = name.endsWith(SETTER_SUFFIX);
+ def isLocalDummyName(name: Name) = name.startsWith(LOCALDUMMY_PREFIX);
+
+// def originalName(name: Name): Name = {
+ def originalName(name: Name): Name = {
+ var i = name.length;
+ while (i >= 2 && !(name(i - 1) == '$' && name(i - 2) == '$')) i = i - 1;
+ if (i >= 2) {
+ while (i >= 3 && name(i - 3) == '$') i = i - 1;
+ name.subName(i, name.length)
+ } else name
+ }
+// val result = originalName(name);
+// System.out.println("oroginal " + name + " = " + result);
+// result
+// }
+
+ def localToGetter(name: Name): Name = {
+ assert(isLocalName(name));//debug
+ name.subName(0, name.length - LOCAL_SUFFIX.length);
+ }
+
+ def getterToLocal(name: Name): Name = {
+ assert(!isLocalName(name) && !isSetterName(name));//debug
+ newTermName(name.toString() + LOCAL_SUFFIX);
+ }
+
+ def getterToSetter(name: Name): Name = {
+ assert(!isLocalName(name) && !isSetterName(name));//debug
+ newTermName(name.toString() + SETTER_SUFFIX);
+ }
+
+ def setterToGetter(name: Name): Name = {
+ name.subName(0, name.length - SETTER_SUFFIX.length);
+ }
+
+ def getterName(name: Name): Name =
+ if (isLocalName(name)) localToGetter(name) else name;
+
+ def isImplClassName(name: Name): boolean =
+ name endsWith IMPL_CLASS_SUFFIX;
+
+ def implClassName(name: Name): Name =
+ newTypeName(name.toString() + IMPL_CLASS_SUFFIX);
+
+ def moduleVarName(name: Name): Name =
+ newTermName(name.toString() + MODULE_SUFFIX);
+
+ def isModuleVarName(name: Name): boolean =
+ name.endsWith(MODULE_SUFFIX);
+
+ def superName(name: Name) = newTermName("super$" + name);
+
+ val ERROR = newTermName("<error>");
+ val ERRORtype = newTypeName("<error>");
+
+ val NOSYMBOL = newTermName("<none>");
+ val EMPTY = newTermName("");
+ val ANYNAME = newTermName("<anyname>");
+ val WILDCARD = newTermName("_");
+ val WILDCARD_STAR = newTermName("_*");
+ val COMPOUND_NAME = newTermName("<ct>");
+ val ANON_CLASS_NAME = newTermName("$anon");
+ val ANON_FUN_NAME = newTermName("$anonfun");
+ val REFINE_CLASS_NAME = newTermName("<refinement>");
+ val EMPTY_PACKAGE_NAME = newTermName("<empty>");
+ val IMPORT = newTermName("<import>");
+ val ZERO = newTermName("<zero>");
+ val STAR = newTermName("*");
+ val ROOT = newTermName("<root>");
+ val REPEATED_PARAM_CLASS_NAME = newTermName("<repeated>");
+ val BYNAME_PARAM_CLASS_NAME = newTermName("<byname>");
+ val SELF = newTermName("$this");
+
+ val CONSTRUCTOR = newTermName("<init>");
+ val MIXIN_CONSTRUCTOR = newTermName("$init$");
+ val INITIALIZER = newTermName("<init>");
+ val INLINED_INITIALIZER = newTermName("$init$");
+
+ val MINUS = encode("-");
+ val PLUS = encode("+");
+ val TILDE = encode("~");
+ val EQEQ = encode("==");
+ val BANG = encode("!");
+ val BANGEQ = encode("!=");
+ val BARBAR = encode("||");
+ val AMPAMP = encode("&&");
+ val COLONCOLON = encode("::");
+ val PERCENT = encode("%");
+
+ val All = newTermName("All");
+ val AllRef = newTermName("AllRef");
+ val Any = newTermName("Any");
+ val AnyVal = newTermName("AnyVal");
+ val AnyRef = newTermName("AnyRef");
+ val Array = newTermName("Array");
+ val Byte = newTermName("Byte");
+ val CaseClass = newTermName("CaseClass");
+ val Catch = newTermName("Catch");
+ val Char = newTermName("Char");
+ val Boolean = newTermName("Boolean");
+ val Do = newTermName("Do");
+ val Double = newTermName("Double");
+ val Element = newTermName("Element");
+ val Finally = newTermName("Finally");
+ val Float = newTermName("Float");
+ val Function = newTermName("Function");
+ val Int = newTermName("Int");
+ val Labelled = newTermName("Labelled");
+ val List = newTermName("List");
+ val Long = newTermName("Long");
+ val Nil = newTermName("Nil");
+ val Object = newTermName("Object");
+ val PartialFunction = newTermName("PartialFunction");
+ val Predef = newTermName("Predef");
+ val ScalaObject = newTermName("ScalaObject");
+ val ScalaRunTime = newTermName("ScalaRunTime");
+ val Seq = newTermName("Seq");
+ val Short = newTermName("Short");
+ val SourceFile = newTermName("SourceFile");
+ val String = newTermName("String");
+ val Symbol = newTermName("Symbol");
+ val Synthetic = newTermName("Synthetic");
+
+ val Text = newTermName("Text");
+ val Throwable = newTermName("Throwable");
+ val Try = newTermName("Try");
+ val Tuple = newTermName("Tuple");
+ val Type = newTermName("Type");
+ val Tuple2 = newTermName("Tuple2");
+ val Unit = newTermName("Unit");
+ val While = newTermName("While");
+ val apply = newTermName("apply");
+ val array = newTermName("array");
+ val assert_ = newTermName("assert");
+ val assume_ = newTermName("assume");
+ val asInstanceOf = newTermName("asInstanceOf");
+ val asInstanceOfErased = newTermName("asInstanceOf$erased");
+ val box = newTermName("box");
+ val caseArity = newTermName("caseArity");
+ val caseElement = newTermName("caseElement");
+ val caseName = newTermName("caseName");
+ val checkCastability = newTermName("checkCastability");
+ val coerce = newTermName("coerce");
+ val defaultValue = newTermName("defaultValue");
+ val dummy = newTermName("$dummy");
+ val elem = newTermName("elem");
+ val elements = newTermName("elements");
+ val eq = newTermName("eq");
+ val equals_ = newTermName("equals");
+ val fail = newTermName("fail");
+ val report = newTermName("report");
+ val false_ = newTermName("false");
+ val filter = newTermName("filter");
+ val finalize_ = newTermName("finalize");
+ val flatMap = newTermName("flatMap");
+ val foreach = newTermName("foreach");
+ val getClass_ = newTermName("getClass");
+ val hasAsInstance = newTermName("hasAsInstance");
+ val hashCode_ = newTermName("hashCode");
+ val hasNext = newTermName("hasNext");
+ val head = newTermName("head");
+ val isInstanceOf = newTermName("isInstanceOf");
+ val isInstanceOfErased = newTermName("isInstanceOf$erased");
+ val isDefinedAt = newTermName("isDefinedAt");
+ val isEmpty = newTermName("isEmpty");
+ val java = newTermName("java");
+ val lang = newTermName("lang");
+ val length = newTermName("length");
+ val map = newTermName("map");
+ val n = newTermName("n");
+ val nobinding = newTermName("nobinding");
+ val next = newTermName("next");
+ val newArray = newTermName("newArray");
+ val notify_ = newTermName("notify");
+ val notifyAll_ = newTermName("notifyAll");
+ val null_ = newTermName("null");
+ val predef = newTermName("predef");
+ val print = newTermName("print");
+ val runtime = newTermName("runtime");
+ val readResolve = newTermName("readResolve");
+ val scala_ = newTermName("scala");
+ val xml = newTermName("xml");
+ val synchronized_ = newTermName("synchronized");
+ val tail = newTermName("tail");
+ val toString_ = newTermName("toString");
+ val that = newTermName("that");
+ val that1 = newTermName("that1");
+ val this_ = newTermName("this");
+ val throw_ = newTermName("throw");
+ val true_ = newTermName("true");
+ val update = newTermName("update");
+ val view_ = newTermName("view");
+ val tag = newTermName("$tag");
+ val wait_ = newTermName("wait");
+
+ val ZNOT = encode("!");
+ val ZAND = encode("&&");
+ val ZOR = encode("||");
+ val NOT = encode("~");
+ val ADD = encode("+");
+ val SUB = encode("-");
+ val MUL = encode("*");
+ val DIV = encode("/");
+ val MOD = encode("%");
+ val EQ = encode("==");
+ val NE = encode("!=");
+ val LT = encode("<");
+ val LE = encode("<=");
+ val GT = encode(">");
+ val GE = encode(">=");
+ val OR = encode("|");
+ val XOR = encode("^");
+ val AND = encode("&");
+ val LSL = encode("<<");
+ val LSR = encode(">>>");
+ val ASR = encode(">>");
+
+ // value-conversion methods
+ val toByte = newTermName("toByte");
+ val toShort = newTermName("toShort");
+ val toChar = newTermName("toChar");
+ val toInt = newTermName("toInt");
+ val toLong = newTermName("toLong");
+ val toFloat = newTermName("toFloat");
+ val toDouble = newTermName("toDouble");
+
+ val SourceFileATTR = newTermName("SourceFile");
+ val SyntheticATTR = newTermName("Synthetic");
+ val BridgeATTR = newTermName("Bridge");
+ val DeprecatedATTR = newTermName("Deprecated");
+ val CodeATTR = newTermName("Code");
+ val ExceptionsATTR = newTermName("Exceptions");
+ val ConstantValueATTR = newTermName("ConstantValue");
+ val LineNumberTableATTR = newTermName("LineNumberTable");
+ val LocalVariableTableATTR = newTermName("LocalVariableTable");
+ val InnerClassesATTR = newTermName("InnerClasses");
+ val JacoMetaATTR = newTermName("JacoMeta");
+ val ScalaSignatureATTR = newTermName("ScalaSig");
+ val JavaInterfaceATTR = newTermName("JacoInterface");
+
+ // '_' is temporary
+ val _Attribute = newTypeName("Attribute");
+ val _MetaData = newTypeName("MetaData");
+ val _NamespaceBinding = newTypeName("NamespaceBinding");
+ val _NodeBuffer = newTypeName("NodeBuffer");
+ val _Null = newTermName("Null");
+
+ val _PrefixedAttribute = newTypeName("PrefixedAttribute");
+ val _UnprefixedAttribute = newTypeName("UnprefixedAttribute");
+ val _Elem = newTypeName("Elem");
+ val _Seq = newTypeName("Seq");
+ val _immutable = newTermName("immutable");
+ val _mutable = newTermName("mutable");
+ val _append = newTermName("append");
+ val _plus = newTermName("$amp$plus");
+ val _collection = newTermName("collection");
+ val _toList = newTermName("toList");
+ val _xml = newTermName("xml");
+ val _Comment = newTypeName("Comment");
+ val _CharData = newTypeName("CharData");
+ val _Node = newTypeName("Node");
+ val _None = newTermName("None");
+ val _Some = newTypeName("Some");
+ val _ProcInstr = newTypeName("ProcInstr");
+ val _Text = newTypeName("Text");
+ val _EntityRef = newTypeName("EntityRef");
+ final val _md = newTermName("$md");
+ final val _scope = newTermName("$scope");
+ final val _tmpscope = newTermName("$tmpscope");
+
+ }
+
+ def encode(str: String): Name = newTermName(NameTransformer.encode(str));
+}
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
new file mode 100644
index 0000000000..11f0c21c4f
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
@@ -0,0 +1,192 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.symtab;
+
+import java.io.IOException;
+import scala.tools.nsc.util.Position;
+import scala.tools.util.{AbstractFile};
+import scala.tools.nsc.util.NameTransformer;
+import scala.collection.mutable.HashMap;
+import classfile.{ClassfileParser, SymblfileParser};
+import Flags._;
+
+
+abstract class SymbolLoaders {
+ val global: Global;
+ import global._;
+
+ /** A lazy type that completes itself by calling parameter doComplete.
+ * Any linked modules/classes or module classes are also initialized.
+ * @param doComplete The type completion procedure to be run.
+ * It takes symbol to compkete as parameter and returns
+ * name of file loaded for completion as a result.
+ * Can throw an IOException on error.
+ */
+ abstract class SymbolLoader(file: AbstractFile) extends LazyType {
+ /** Load source or class file for `root', return */
+ protected def doComplete(root: Symbol): unit;
+ /** The kind of file that's processed by this loader */
+ protected def kindString: String;
+ private var ok = false;
+ private def setSource(sym: Symbol): unit = sym match {
+ case clazz: ClassSymbol => clazz.sourceFile = file;
+ case _ =>
+ }
+ override def complete(root: Symbol): unit = {
+ try {
+ val start = System.currentTimeMillis();
+ val currentphase = phase;
+ doComplete(root);
+ phase = currentphase;
+ def source = kindString + " " + file;
+ informTime("loaded " + source, start);
+ if (root.rawInfo != this) {
+ ok = true;
+ setSource(root.linkedModule);
+ setSource(root.linkedClass);
+ } else error(source + " does not define " + root)
+ } catch {
+ case ex: IOException =>
+ if (settings.debug.value) ex.printStackTrace();
+ val msg = ex.getMessage();
+ error(
+ if (msg == null) "i/o error while loading " + root.name
+ else "error while loading " + root.name + ", " + msg);
+ }
+ initRoot(root);
+ if (!root.isPackageClass) initRoot(root.linkedSym);
+ }
+ override def load(root: Symbol): unit = complete(root);
+
+ private def initRoot(root: Symbol): unit = {
+ if (root.rawInfo == this) {
+ root.setInfo(if (ok) NoType else ErrorType);
+ if (root.isModule)
+ root.moduleClass.setInfo(if (ok) NoType else ErrorType)
+ }
+ if (root.isClass && !root.isModuleClass) root.rawInfo.load(root)
+ }
+ }
+
+ /** Load contents of a package
+ */
+ class PackageLoader(directory: AbstractFile) extends SymbolLoader(directory) {
+ protected def doComplete(root: Symbol): unit = {
+ assert(root.isPackageClass, root);
+ root.setInfo(new PackageClassInfoType(new Scope(), root));
+
+ /** Is the given name a valid input file base name? */
+ def isValid(name: String): boolean =
+ name.length() > 0 && !name.endsWith("$class") && name.indexOf("$anon") == -1;
+
+ def enterPackage(str: String, completer: SymbolLoader): unit = {
+ val pkg = root.newPackage(Position.NOPOS, newTermName(str));
+ pkg.moduleClass.setInfo(completer);
+ pkg.setInfo(pkg.moduleClass.tpe);
+ root.info.decls.enter(pkg)
+ }
+
+ def enterClassAndModule(str: String, completer: SymbolLoader, sfile : AbstractFile): unit = {
+ val owner = if (root.isRoot) definitions.EmptyPackageClass else root;
+ val name = newTermName(str);
+ val clazz = owner.newClass(Position.NOPOS, name.toTypeName);
+ val module = owner.newModule(Position.NOPOS, name);
+ clazz.sourceFile = sfile;
+ clazz.setInfo(completer);
+ module.setInfo(completer);
+ module.moduleClass.setInfo(moduleClassLoader);
+ owner.info.decls.enter(clazz);
+ owner.info.decls.enter(module);
+ assert(clazz.linkedModule == module, module);
+ assert(module.linkedClass == clazz, clazz);
+ }
+
+ val sources = new HashMap[String, AbstractFile];
+ val classes = new HashMap[String, AbstractFile];
+ val packages = new HashMap[String, AbstractFile];
+ val it = directory.list();
+ while (it.hasNext()) {
+ val file = it.next().asInstanceOf[AbstractFile];
+ val filename = file.getName();
+ if (file.isDirectory()) {
+ if (filename != "META_INF" && !packages.isDefinedAt(filename)) packages(filename) = file;
+/*
+ } else if (filename.endsWith(".symbl")) {
+ val name = filename.substring(0, filename.length() - 6);
+ if (isValid(name) &&
+ (!classes.isDefinedAt(name) || classes(name).getName().endsWith(".class")))
+ classes(name) = file;
+*/
+ } else if (filename.endsWith(".class")) {
+ val name = filename.substring(0, filename.length() - 6);
+ if (isValid(name) && !classes.isDefinedAt(name))
+ classes(name) = file;
+ } else if (filename.endsWith(".scala")) {
+ val name = filename.substring(0, filename.length() - 6);
+ if (isValid(name) && !sources.isDefinedAt(name))
+ sources(name) = file;
+ }
+ }
+ for (val Pair(name, sfile) <- sources.elements) {
+ classes.get(name) match {
+ case Some(cfile) if (cfile.lastModified() >= sfile.lastModified()) => {}
+ case _ => enterClassAndModule(name, new SourcefileLoader(sfile), sfile);
+ }
+ }
+ for (val Pair(name, cfile) <- classes.elements) {
+ val sfile = sources.get(name) match {
+ case Some(sfile0) => sfile0;
+ case _ => null;
+ }
+ sources.get(name) match {
+ case Some(sfile) if (sfile.lastModified() > cfile.lastModified()) => {}
+ case _ =>
+ val loader =
+/* if (cfile.getName().endsWith(".symbl")) new SymblfileLoader(cfile)
+ else */
+ new ClassfileLoader(cfile);
+ enterClassAndModule(name, loader, sfile)
+ }
+ }
+ for (val Pair(name, file) <- packages.elements) {
+ if (!sources.contains(name) && !classes.contains(name))
+ enterPackage(name, new PackageLoader(file));
+ }
+ }
+ protected def kindString: String = "directory path"
+ }
+
+ private object classfileParser extends ClassfileParser {
+ val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global;
+ }
+
+/*
+ private object symblfileParser extends SymblfileParser {
+ val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global;
+ }
+*/
+
+ class ClassfileLoader(file: AbstractFile) extends SymbolLoader(file) {
+ protected def doComplete(root: Symbol): unit = classfileParser.parse(file, root);
+ protected def kindString: String = "class file";
+ }
+/*
+ class SymblfileLoader(file: AbstractFile) extends SymbolLoader(file) {
+ protected def doComplete(root: Symbol): unit = symblfileParser.parse(file, root);
+ protected def kindString: String = "symbl file";
+ }
+*/
+ class SourcefileLoader(file: AbstractFile) extends SymbolLoader(file) {
+ protected def doComplete(root: Symbol): unit = global.currentRun.compileLate(file);
+ protected def kindString: String = "source file";
+ }
+
+ object moduleClassLoader extends SymbolLoader(null) {
+ protected def doComplete(root: Symbol): unit =
+ root.sourceModule.initialize;
+ protected def kindString: String = "";
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
new file mode 100644
index 0000000000..eb29dad289
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
@@ -0,0 +1,50 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.symtab;
+
+import util._;
+
+abstract class SymbolTable extends Names
+ with Symbols
+ with Types
+ with Scopes
+ with Definitions
+ with Constants
+ with InfoTransformers
+ with StdNames {
+ def settings: Settings;
+ def rootLoader: LazyType;
+ def log(msg: Object): unit;
+
+ private var ph: Phase = NoPhase;
+ def phase: Phase = ph;
+ def phase_=(p: Phase): unit = {
+ //System.out.println("setting phase to " + p);
+ assert(p != null && p != NoPhase);
+ ph = p
+ }
+
+ final val NoRun = null;
+
+ /** The current compiler run. */
+ def currentRun: CompilerRun;
+
+ def atPhase[T](ph: Phase)(op: => T): T = {
+ val current = phase;
+ phase = ph;
+ val result = op;
+ phase = current;
+ result
+ }
+
+ var infoTransformers = new InfoTransformer {
+ val pid = NoPhase.id;
+ val changesBaseClasses = true;
+ def transform(sym: Symbol, tpe: Type): Type = tpe;
+ }
+
+ val phaseWithId: Array[Phase];
+}
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
new file mode 100644
index 0000000000..6bdf29c54e
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -0,0 +1,1055 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.symtab;
+
+import scala.tools.util.AbstractFile;
+import scala.tools.nsc.util.{Position, SourceFile};
+import Flags._;
+
+[_trait_] abstract class Symbols: SymbolTable {
+ import definitions._;
+
+ private var ids = 0;
+
+ //for statistics:
+ def symbolCount = ids;
+ var typeSymbolCount = 0;
+ var classSymbolCount = 0;
+
+ type AttrInfo = Pair[Type, List[Constant]];
+
+ val emptySymbolArray = new Array[Symbol](0);
+
+ /** The class for all symbols */
+ abstract class Symbol(initOwner: Symbol, initPos: int, initName: Name) {
+
+ var rawowner = initOwner;
+ var rawname = initName;
+ private var rawflags: long = 0;
+ private var rawpos = initPos;
+ val id = { ids = ids + 1; ids }
+
+ var validForRun: CompilerRun = NoRun;
+
+ def pos = rawpos;
+ def setPos(pos: int): this.type = { this.rawpos = pos; this }
+
+ def namePos(source : SourceFile) = {
+ val buf = source.content;
+ if (pos == Position.NOPOS) Position.NOPOS;
+ else if (isTypeParameter) pos - name.length;
+ else if (isVariable || isMethod || isClass || isModule) {
+ var ret = pos;
+
+ if (buf(pos) == ',') ret = ret + 1;
+ else if (isClass) ret = ret + ("class").length();
+ else if (isModule) ret = ret + ("object").length();
+ else ret = ret + ("var").length();
+ while (Character.isWhitespace(buf(ret))) ret = ret + 1;
+ ret;
+ }
+ else if (isValue) pos;
+ else -1;
+ }
+
+ var attributes: List[AttrInfo] = List();
+
+ var privateWithin: Symbol = null;
+
+// Creators -------------------------------------------------------------------
+
+ final def newValue(pos: int, name: Name) =
+ new TermSymbol(this, pos, name);
+ final def newVariable(pos: int, name: Name) =
+ newValue(pos, name).setFlag(MUTABLE);
+ final def newValueParameter(pos: int, name: Name) =
+ newValue(pos, name).setFlag(PARAM);
+ final def newLocalDummy(pos: int) =
+ newValue(pos, nme.LOCAL(this)).setInfo(NoType);
+ final def newMethod(pos: int, name: Name) =
+ newValue(pos, name).setFlag(METHOD);
+ final def newLabel(pos: int, name: Name) =
+ newMethod(pos, name).setFlag(LABEL);
+ final def newConstructor(pos: int) =
+ newMethod(pos, nme.CONSTRUCTOR);
+ final def newModule(pos: int, name: Name, clazz: ClassSymbol) =
+ new ModuleSymbol(this, pos, name).setFlag(MODULE | FINAL).setModuleClass(clazz);
+ final def newModule(pos: int, name: Name) = {
+ val m = new ModuleSymbol(this, pos, name).setFlag(MODULE | FINAL);
+ m.setModuleClass(new ModuleClassSymbol(m))
+ }
+ final def newPackage(pos: int, name: Name) = {
+ assert(isPackageClass);
+ val m = newModule(pos, name).setFlag(JAVA | PACKAGE);
+ m.moduleClass.setFlag(JAVA | PACKAGE);
+ m
+ }
+ final def newThisSym(pos: int) = {
+ newValue(pos, nme.this_).setFlag(SYNTHETIC);
+ }
+ final def newThisSkolem: Symbol =
+ new ThisSkolem(owner, pos, name, this)
+ .setFlag(SYNTHETIC | FINAL);
+ final def newImport(pos: int) =
+ newValue(pos, nme.IMPORT).setFlag(SYNTHETIC);
+ final def newOverloaded(pre: Type, alternatives: List[Symbol]): Symbol =
+ newValue(alternatives.head.pos, alternatives.head.name)
+ .setFlag(OVERLOADED)
+ .setInfo(OverloadedType(pre, alternatives));
+
+ final def newErrorValue(name: Name) =
+ newValue(pos, name).setFlag(SYNTHETIC | IS_ERROR).setInfo(ErrorType);
+ final def newAliasType(pos: int, name: Name) =
+ new TypeSymbol(this, pos, name);
+ final def newAbstractType(pos: int, name: Name) =
+ new TypeSymbol(this, pos, name).setFlag(DEFERRED);
+ final def newTypeParameter(pos: int, name: Name) =
+ newAbstractType(pos, name).setFlag(PARAM);
+ final def newTypeSkolem: Symbol =
+ new TypeSkolem(owner, pos, name, this)
+ .setFlag(flags);
+ final def newClass(pos: int, name: Name) =
+ new ClassSymbol(this, pos, name);
+ final def newModuleClass(pos: int, name: Name) =
+ new ModuleClassSymbol(this, pos, name);
+ final def newAnonymousClass(pos: int) =
+ newClass(pos, nme.ANON_CLASS_NAME.toTypeName);
+ final def newAnonymousFunctionClass(pos: int) =
+ newClass(pos, nme.ANON_FUN_NAME.toTypeName);
+ final def newRefinementClass(pos: int) =
+ newClass(pos, nme.REFINE_CLASS_NAME.toTypeName);
+ final def newErrorClass(name: Name) = {
+ val clazz = newClass(pos, name).setFlag(SYNTHETIC | IS_ERROR);
+ clazz.setInfo(ClassInfoType(List(), new ErrorScope(this), clazz));
+ clazz
+ }
+ final def newErrorSymbol(name: Name): Symbol =
+ if (name.isTypeName) newErrorClass(name) else newErrorValue(name);
+
+// Tests ----------------------------------------------------------------------
+
+ def isTerm = false; //to be overridden
+ def isType = false; //to be overridden
+ def isClass = false; //to be overridden
+
+ final def isValue = isTerm && !(isModule && hasFlag(PACKAGE | JAVA));
+ final def isVariable = isTerm && hasFlag(MUTABLE) && !isMethod;
+ final def isCapturedVariable = isVariable && hasFlag(CAPTURED);
+
+ final def isSetter = isTerm && hasFlag(ACCESSOR) && nme.isSetterName(name);
+ //todo: make independent of name, as this can be forged.
+ final def hasGetter = isTerm && nme.isLocalName(name);
+ final def isValueParameter = isTerm && hasFlag(PARAM);
+ final def isLocalDummy = isTerm && nme.isLocalDummyName(name);
+ final def isMethod = isTerm && hasFlag(METHOD);
+ final def isSourceMethod = isTerm && (flags & (METHOD | STABLE)) == METHOD;
+ final def isLabel = isTerm && hasFlag(LABEL);
+ final def isClassConstructor = isTerm && (name == nme.CONSTRUCTOR);
+ final def isMixinConstructor = isTerm && (name == nme.MIXIN_CONSTRUCTOR);
+ final def isConstructor = isTerm && (name == nme.CONSTRUCTOR) || (name == nme.MIXIN_CONSTRUCTOR);
+ final def isModule = isTerm && hasFlag(MODULE);
+ final def isStaticModule = isModule && isStatic && !isMethod;
+ final def isPackage = isModule && hasFlag(PACKAGE);
+ final def isThisSym = isTerm && name == nme.this_;
+ final def isThisSkolem = isTerm && deSkolemize != this;
+ final def isError = hasFlag(IS_ERROR);
+ final def isTrait = isClass & hasFlag(TRAIT);
+ final def isAliasType = isType && !isClass && !hasFlag(DEFERRED);
+ final def isAbstractType = isType && !isClass && hasFlag(DEFERRED);
+ final def isTypeParameterOrSkolem = isType && hasFlag(PARAM);
+ final def isTypeParameter = isTypeParameterOrSkolem && deSkolemize == this;
+ final def isClassLocalToConstructor = isClass && hasFlag(INCONSTRUCTOR);
+ final def isAnonymousClass = isClass && (originalName startsWith nme.ANON_CLASS_NAME);
+ // startsWith necessary because name may grow when lifted and also because of anonymous function classes
+ final def isRefinementClass = isClass && name == nme.REFINE_CLASS_NAME.toTypeName; // no lifting for refinement classes
+ final def isModuleClass = isClass && hasFlag(MODULE);
+ final def isPackageClass = isClass && hasFlag(PACKAGE);
+ final def isRoot = isPackageClass && name == nme.ROOT.toTypeName;
+ final def isRootPackage = isPackage && name == nme.ROOT;
+ final def isEmptyPackage = isPackage && name == nme.EMPTY_PACKAGE_NAME;
+ final def isEmptyPackageClass = isPackageClass && name == nme.EMPTY_PACKAGE_NAME.toTypeName;
+
+ /** Does this symbol denote a stable value? */
+ final def isStable =
+ isTerm && !hasFlag(MUTABLE) && (!hasFlag(METHOD | BYNAMEPARAM) || hasFlag(STABLE));
+
+ /** Does this symbol denote the primary constructor
+ * of its enclosing class or trait? */
+ final def isPrimaryConstructor =
+ isConstructor && owner.primaryConstructor == this;
+
+ /** Is this symbol an implementation class for a trait ? */
+ final def isImplClass: boolean = isClass && hasFlag(IMPLCLASS);
+
+ final def needsImplClass: boolean =
+ isTrait && (!hasFlag(INTERFACE) || hasFlag(lateINTERFACE)) && !isImplClass;
+
+ final def isImplOnly: boolean = (
+ hasFlag(PRIVATE) ||
+ (owner.isImplClass || owner.isTrait) &&
+ (hasFlag(notPRIVATE | LIFTED) && !hasFlag(ACCESSOR | SUPERACCESSOR) ||
+ isConstructor)
+ );
+
+ /** Is this symbol a module variable ? */
+ final def isModuleVar: boolean = isVariable && nme.isModuleVarName(name);
+
+ /** Is this symbol static (i.e. with no outer instance)? */
+ final def isStatic: boolean =
+ hasFlag(STATIC) || isRoot || owner.isStaticOwner;
+
+ /** Does this symbol denote a class that defines static symbols? */
+ final def isStaticOwner: boolean =
+ isPackageClass || isModuleClass && isStatic;
+
+ /** Is this symbol final?*/
+ final def isFinal: boolean = (
+ hasFlag(FINAL) ||
+ isTerm && (
+ hasFlag(PRIVATE) || isLocal || owner.isClass && owner.hasFlag(FINAL | MODULE))
+ );
+
+ /** Is this symbol a sealed class?*/
+ final def isSealed: boolean =
+ isClass && (hasFlag(SEALED) || isUnboxedClass(this));
+
+ /** Is this symbol locally defined? I.e. not accessed from outside `this' instance */
+ final def isLocal: boolean = owner.isTerm;
+
+ /** Is this symbol a constant? */
+ final def isConstant: boolean =
+ isStable && (tpe match {
+ case ConstantType(_) => true
+ case PolyType(_, ConstantType(_)) => true
+ case MethodType(_, ConstantType(_)) => true
+ case _ => false
+ });
+
+ /** Is this class nested in another class or module (not a package)? */
+ final def isNestedClass: boolean =
+ isClass && !isRoot && !owner.isPackageClass;
+
+ /** Is this class locally defined?
+ * A class is local, if
+ * - it is anonymous, or
+ * - its owner is a value
+ * - it is defined within a local class214
+ */
+ final def isLocalClass: boolean =
+ isClass && (isAnonymousClass || isRefinementClass || isLocal ||
+ !owner.isPackageClass && owner.isLocalClass);
+
+ /** Symbol was preloaded from package */
+ final def isExternal: boolean = rawpos == Position.NOPOS;
+
+ /** A a member of class `base' is incomplete if (1) it is declared deferred or
+ * (2) it is abstract override and its super symbol in `base' is nonexistent or inclomplete.
+ */
+ final def isIncompleteIn(base: Symbol): boolean = (
+ (this hasFlag DEFERRED) ||
+ (this hasFlag ABSOVERRIDE) && {
+ val supersym = superSymbol(base);
+ supersym == NoSymbol || supersym.isIncompleteIn(base)
+ }
+ );
+
+ final def isInitialized: boolean =
+ validForRun == currentRun;
+
+ /** The variance of this symbol as an integer */
+ final def variance: int =
+ if (hasFlag(COVARIANT)) 1
+ else if (hasFlag(CONTRAVARIANT)) -1
+ else 0;
+
+// Flags, owner, and name attributes --------------------------------------------------------------
+
+ def owner: Symbol = rawowner;
+ final def owner_=(owner: Symbol): unit = { rawowner = owner }
+
+ def ownerChain: List[Symbol] = this :: owner.ownerChain;
+
+ def name: Name = rawname;
+ final def name_=(name: Name): unit = { rawname = name }
+
+ def originalName = nme.originalName(name);
+
+ final def flags = {
+ val fs = rawflags & phase.flagMask;
+ (fs | ((fs & LateFlags) >>> LateShift)) & ~(fs >>> AntiShift)
+ }
+ final def flags_=(fs: long) = rawflags = fs;
+ final def setFlag(mask: long): this.type = { rawflags = rawflags | mask; this }
+ final def resetFlag(mask: long): this.type = { rawflags = rawflags & ~mask; this }
+ final def getFlag(mask: long): long = flags & mask;
+ final def hasFlag(mask: long): boolean = (flags & mask) != 0;
+ final def resetFlags: unit = { rawflags = rawflags & TopLevelCreationFlags }
+
+// Info and Type -------------------------------------------------------------------
+
+ private var infos: TypeHistory = null;
+ private var limit: Phase#Id = 0;
+
+ /** Get type. The type of a symbol is:
+ * for a type symbol, the type corresponding to the symbol itself
+ * for a term symbol, its usual type
+ */
+ def tpe: Type = info;
+
+ /** Get type info associated with symbol at current phase, after
+ * ensuring that symbol is initialized (i.e. type is completed).
+ */
+ final def info: Type = {
+ var cnt = 0;
+ while (validForRun != currentRun) {
+ //if (settings.debug.value) System.out.println("completing " + this);//DEBUG
+ var ifs = infos;
+ assert(ifs != null, this.name);
+ while (ifs.prev != null) {
+ ifs = ifs.prev;
+ }
+ val tp = ifs.info;
+ //if (settings.debug.value) System.out.println("completing " + this.rawname + tp.getClass());//debug
+ if ((rawflags & LOCKED) != 0) {
+ setInfo(ErrorType);
+ throw CyclicReference(this, tp);
+ }
+ rawflags = rawflags | LOCKED;
+ val current = phase;
+ try {
+ phase = phaseWithId(ifs.start);
+ tp.complete(this);
+ // if (settings.debug.value && (validForRun == currentRun) System.out.println("completed " + this/* + ":" + info*/);//DEBUG
+ rawflags = rawflags & ~LOCKED
+ } finally {
+ phase = current
+ }
+ cnt = cnt + 1;
+ // allow for two completions:
+ // one: sourceCompleter to LazyType, two: LazyType to completed type
+ if (cnt == 3) throw new Error("no progress in completing " + this + ":" + tp);
+ }
+ rawInfo
+ }
+
+ /** Set initial info. */
+ def setInfo(info: Type): this.type = {
+ assert(info != null);
+ var pid = phase.id;
+ if (pid == 0) {
+ // can happen when we initialize NoSymbol before running the compiler
+ assert(name == nme.NOSYMBOL);
+ pid = 1
+ }
+ infos = new TypeHistory(pid, info, null);
+ limit = pid;
+ if (info.isComplete) {
+ rawflags = rawflags & ~LOCKED;
+ validForRun = currentRun
+ } else {
+ rawflags = rawflags & ~LOCKED;
+ validForRun = NoRun
+ }
+ this
+ }
+
+ /** Set new info valid from start of this phase. */
+ final def updateInfo(info: Type): Symbol = {
+ assert(infos.start <= phase.id);
+ if (infos.start == phase.id) infos = infos.prev;
+ infos = new TypeHistory(phase.id, info, infos);
+ this
+ }
+
+ /** Return info without checking for initialization or completing */
+ final def rawInfo: Type = {
+ if (limit < phase.id) {
+ if (validForRun == currentRun) {
+ val current = phase;
+ var itr = infoTransformers.nextFrom(limit);
+ infoTransformers = itr; // caching optimization
+ while (itr.pid != NoPhase.id && itr.pid < current.id) {
+ phase = phaseWithId(itr.pid);
+ val info1 = itr.transform(this, infos.info);
+ limit = phase.id + 1;
+ if (info1 ne infos.info) {
+ infos = new TypeHistory(limit, info1, infos);
+ }
+ itr = itr.nextFrom(limit)
+ }
+ phase = current;
+ limit = current.id;
+ }
+ assert(infos != null, name);
+ infos.info
+ } else {
+ var infos = this.infos;
+ while (phase.id < infos.start && infos.prev != null) infos = infos.prev;
+ infos.info
+ }
+ }
+
+ /** Initialize the symbol */
+ final def initialize: this.type = {
+ if (!isInitialized) info;
+ this
+ }
+
+ /** Was symbol's type updated during given phase? */
+ final def isUpdatedAt(pid: Phase#Id): boolean = {
+ var infos = this.infos;
+ while (infos != null && infos.start != pid + 1) infos = infos.prev;
+ infos != null
+ }
+
+ /** The type constructor of a symbol is:
+ * For a type symbol, the type corresponding to the symbol itself,
+ * excluding parameters.
+ * Not applicable for term symbols.
+ */
+ def typeConstructor: Type = throw new Error("typeConstructor inapplicable for " + this);
+
+ /** The type parameters of this symbol */
+ def unsafeTypeParams: List[Symbol] = rawInfo.typeParams;
+
+ def typeParams: List[Symbol] = {
+ rawInfo.load(this); rawInfo.typeParams
+ }
+
+ /** Reset symbol to initial state
+ */
+ def reset(completer: Type): unit = {
+ resetFlags;
+ rawpos = Position.NOPOS;
+ infos = null;
+ limit = NoPhase.id;
+ setInfo(completer)
+ }
+
+// Comparisons ----------------------------------------------------------------
+
+ /** A total ordering between symbols that refines the class
+ * inheritance graph (i.e. subclass.isLess(superclass) always holds).
+ * the ordering is given by: (isType, -|closure| for type symbols, id)
+ */
+ final def isLess(that: Symbol): boolean = {
+ def closureLength(sym: Symbol) =
+ if (sym.isAbstractType) 1 + sym.info.bounds.hi.closure.length
+ else sym.info.closure.length;
+ if (this.isType)
+ (that.isType &&
+ { val diff = closureLength(this) - closureLength(that);
+ diff > 0 || diff == 0 && this.id < that.id })
+ else
+ that.isType || this.id < that.id;
+ }
+
+ /** A partial ordering between symbols.
+ * (this isNestedIn that) holds iff this symbol is defined within
+ * a class or method defining that symbol
+ */
+ final def isNestedIn(that: Symbol): boolean =
+ owner == that || owner != NoSymbol && (owner isNestedIn that);
+
+ /** Is this class symbol a subclass of that symbol? */
+ final def isSubClass(that: Symbol): boolean = (
+ this == that || this.isError || that.isError ||
+ info.closurePos(that) >= 0 ||
+ this == AllClass ||
+ this == AllRefClass &&
+ (that == AnyClass ||
+ that != AllClass && (that isSubClass AnyRefClass))
+ );
+
+// Overloaded Alternatives ---------------------------------------------------------
+
+ def alternatives: List[Symbol] =
+ if (hasFlag(OVERLOADED)) info.asInstanceOf[OverloadedType].alternatives
+ else List(this);
+
+ def filter(cond: Symbol => boolean): Symbol =
+ if (hasFlag(OVERLOADED)) {
+ //assert(info.isInstanceOf[OverloadedType], "" + this + ":" + info);//DEBUG
+ val alts = alternatives;
+ val alts1 = alts filter cond;
+ if (alts1 eq alts) this
+ else if (alts1.isEmpty) NoSymbol
+ else if (alts1.tail.isEmpty) alts1.head
+ else owner.newOverloaded(info.prefix, alts1)
+ } else if (cond(this)) this
+ else NoSymbol;
+
+ def suchThat(cond: Symbol => boolean): Symbol = {
+ val result = filter(cond);
+ assert(!(result hasFlag OVERLOADED), result.alternatives);
+ result
+ }
+
+// Cloneing -------------------------------------------------------------------
+
+ /** A clone of this symbol */
+ final def cloneSymbol: Symbol =
+ cloneSymbol(owner);
+
+ /** A clone of this symbol, but with given owner */
+ final def cloneSymbol(owner: Symbol): Symbol =
+ cloneSymbolImpl(owner).setInfo(info.cloneInfo(owner)).setFlag(this.rawflags);
+
+ /** Internal method to clone a symbol's implementation without flags or type
+ */
+ def cloneSymbolImpl(owner: Symbol): Symbol;
+
+// Access to related symbols --------------------------------------------------
+
+ /** The next enclosing class */
+ def enclClass: Symbol = if (isClass) this else owner.enclClass;
+
+ /** The next enclosing method */
+ def enclMethod: Symbol = if (isSourceMethod) this else owner.enclMethod;
+
+ /** The primary constructor of a class */
+ def primaryConstructor: Symbol = {
+ val c = info.decl(if (isTrait || isImplClass) nme.MIXIN_CONSTRUCTOR else nme.CONSTRUCTOR);
+ if (c hasFlag OVERLOADED) c.alternatives.head else c
+ }
+
+ /** The self symbol of a class with explicit self type, or else the symbol itself.
+ */
+ def thisSym: Symbol = this;
+
+ /** The type of `this' in a class, or else the type of the symbol itself. */
+ final def typeOfThis = thisSym.tpe;
+
+ /** Sets the type of `this' in a class */
+ def typeOfThis_=(tp: Type): unit = throw new Error("typeOfThis cannot be set for " + this);
+
+ /** If symbol is a class, the type this.type in this class, otherwise NoPrefix */
+ def thisType: Type = NoPrefix;
+
+ /** Return every accessor of a primary constructor parameter in this case class
+ * todo: limit to accessors for first constructor parameter section.
+ */
+ final def caseFieldAccessors: List[Symbol] =
+ info.decls.toList filter (sym => !(sym hasFlag PRIVATE) && sym.hasFlag(CASEACCESSOR));
+
+ final def constrParamAccessors: List[Symbol] =
+ info.decls.toList filter (sym => !sym.isMethod && sym.hasFlag(PARAMACCESSOR));
+
+ /** The symbol accessed by this accessor function.
+ */
+ final def accessed: Symbol = {
+ assert(hasFlag(ACCESSOR));
+ owner.info.decl(nme.getterToLocal(if (isSetter) nme.setterToGetter(name) else name))
+ }
+
+ final def implClass: Symbol = owner.info.decl(nme.implClassName(name));
+
+ /** For a paramaccessor: a superclass paramaccessor for which this symbol is
+ * an alias, NoSymbol for all others */
+ def alias: Symbol = NoSymbol;
+
+ /** The class with the same name in the same package as this module or
+ * case class factory
+ */
+ final def linkedClass: Symbol = {
+ if (owner.isPackageClass)
+ owner.info.decl(name.toTypeName).suchThat(sym => sym.rawInfo ne NoType)
+ else NoSymbol;
+ }
+
+ /** The module or case class factory with the same name in the same
+ * package as this class.
+ */
+ final def linkedModule: Symbol =
+ if (owner.isPackageClass)
+ owner.info.decl(name.toTermName).suchThat(
+ sym => (sym hasFlag MODULE) && (sym.rawInfo ne NoType));
+ else NoSymbol;
+
+ /** The top-level class containing this symbol */
+ def toplevelClass: Symbol =
+ if (isClass && owner.isPackageClass) this else owner.toplevelClass;
+
+ /** For a module its linked class, for a class its linked module or case factory otherwise */
+ final def linkedSym: Symbol =
+ if (isTerm) linkedClass
+ else if (isClass && owner.isPackageClass)
+ owner.info.decl(name.toTermName).suchThat(sym => sym.rawInfo ne NoType)
+ else NoSymbol;
+
+ final def toInterface: Symbol =
+ if (isImplClass) {
+ assert(!tpe.parents.isEmpty, this);
+ tpe.parents.last.symbol
+ } else this;
+
+ /** The module corresponding to this module class (note that this
+ * is not updated when a module is cloned).
+ */
+ def sourceModule: Symbol = NoSymbol;
+
+ /** The module class corresponding to this module.
+ */
+ def moduleClass: Symbol = NoSymbol;
+
+ /** The non-abstract, symbol whose type matches the type of this symbol in in given class
+ * @param ofclazz The class containing the symbol's definition
+ * @param site The base type from which member types are computed
+ */
+ final def matchingSymbol(ofclazz: Symbol, site: Type): Symbol =
+ ofclazz.info.nonPrivateDecl(name).suchThat(sym =>
+ !sym.isTerm || (site.memberType(this) matches site.memberType(sym)));
+
+ /** The symbol overridden by this symbol in given class `ofclazz' */
+ final def overriddenSymbol(ofclazz: Symbol): Symbol =
+ matchingSymbol(ofclazz, owner.thisType);
+
+ /** The symbol overriding this symbol in given subclass `ofclazz' */
+ final def overridingSymbol(ofclazz: Symbol): Symbol =
+ matchingSymbol(ofclazz, ofclazz.thisType);
+
+ /** The symbol accessed by a super in the definition of this symbol when seen from
+ * class `base'. This symbol is always concrete.
+ * pre: `this.owner' is in the base class sequence of `base'.
+ */
+ final def superSymbol(base: Symbol): Symbol = {
+ var bcs = base.info.baseClasses.dropWhile(owner !=).tail;
+ var sym: Symbol = NoSymbol;
+ while (!bcs.isEmpty && sym == NoSymbol) {
+ if (!bcs.head.isImplClass)
+ sym = matchingSymbol(bcs.head, base.thisType).suchThat(
+ sym => !sym.hasFlag(DEFERRED));
+ bcs = bcs.tail
+ }
+ sym
+ }
+
+ /** The getter of this value definition in class `base', or NoSymbol if none exists */
+ final def getter(base: Symbol): Symbol =
+ base.info.decl(nme.getterName(name)) filter (.hasFlag(ACCESSOR));
+
+ /** The setter of this value definition, or NoSymbol if none exists */
+ final def setter(base: Symbol): Symbol =
+ base.info.decl(nme.getterToSetter(nme.getterName(name))) filter (.hasFlag(ACCESSOR));
+
+ /** If this symbol is a skolem, its corresponding type parameter, otherwise this */
+ def deSkolemize: Symbol = this;
+
+ /** Remove private modifier from symbol `sym's definition. If `sym' is a
+ * term symbol rename it by expanding its name to avoid name clashes
+ */
+ final def makeNotPrivate(base: Symbol): unit =
+ if (isTerm && (this hasFlag PRIVATE)) {
+ setFlag(notPRIVATE);
+ if (!hasFlag(DEFERRED)) setFlag(lateFINAL);
+ expandName(base)
+ }
+
+ /** change name by appending $$<fully-qualified-name-of-class `base'>
+ * Do the same for any accessed symbols or setters/getters
+ */
+ def expandName(base: Symbol): unit =
+ if (this != NoSymbol && !hasFlag(EXPANDEDNAME)) {
+ setFlag(EXPANDEDNAME);
+ if (hasFlag(ACCESSOR)) {
+ accessed.expandName(base);
+ } else if (hasGetter) {
+ getter(owner).expandName(base);
+ setter(owner).expandName(base);
+ }
+ name = base.expandedName(name)
+ }
+
+ def expandedName(name: Name): Name =
+ newTermName(fullNameString('$') + nme.EXPAND_SEPARATOR_STRING + name);
+
+/*
+ def referenced: Symbol =
+ throw new Error("referenced inapplicable for " + this);
+
+ def setReferenced(sym: Symbol): Symbol =
+ throw new Error("setReferenced inapplicable for " + this);
+*/
+// ToString -------------------------------------------------------------------
+
+ /** A tag which (in the ideal case) uniquely identifies class symbols */
+ final def tag: int = fullNameString.hashCode();
+
+ /** The simple name of this Symbol (this is always a term name) */
+ final def simpleName: Name = name;
+
+ /** String representation of symbol's definition key word */
+ final def keyString: String =
+ if (isTrait)
+ if (hasFlag(JAVA)) "interface" else "trait"
+ else if (isClass) "class"
+ else if (isType && !hasFlag(PARAM)) "type"
+ else if (isVariable) "var"
+ else if (isPackage) "package"
+ else if (isModule) "object"
+ else if (isMethod) "def"
+ else if (isTerm && (!hasFlag(PARAM) || hasFlag(PARAMACCESSOR))) "val"
+ else "";
+
+ /** String representation of symbol's kind */
+ final def kindString: String =
+ if (isPackageClass)
+ if (settings.debug.value) "package class" else "package"
+ else if (isAnonymousClass) "<template>"
+ else if (isRefinementClass) ""
+ else if (isModuleClass) "singleton class"
+ else if (isTrait) "trait"
+ else if (isClass) "class"
+ else if (isType) "type"
+ else if (isVariable) "variable"
+ else if (isPackage) "package"
+ else if (isModule) "object"
+ else if (isClassConstructor) "constructor"
+ else if (isSourceMethod) "method"
+ else if (isTerm) "value"
+ else "";
+
+ /** String representation of symbol's simple name.
+ * If !settings.debug translates expansions of operators back to operator symbol.
+ * E.g. $eq => =.
+ * If settings.uniquId adds id.
+ */
+ def nameString: String = //todo: should be final
+ simpleName.decode + idString;
+
+ /** String representation of symbol's full name with `separator'
+ * between class names.
+ * Never translates expansions of operators back to operator symbol.
+ * Never adds id.
+ */
+ final def fullNameString(separator: char): String =
+ if (owner.isRoot || owner.isEmptyPackageClass) simpleName.toString()
+ else owner.fullNameString(separator) + separator + simpleName;
+
+ final def fullNameString: String = fullNameString('.');
+
+ /** If settings.uniqid is set, the symbol's id, else "" */
+ final def idString: String =
+ if (settings.uniqid.value) "#" + id else "";
+
+ /** String representation, including symbol's kind
+ * e.g., "class Foo", "method Bar".
+ */
+ override def toString(): String =
+ compose(List(kindString, if (isClassConstructor) owner.nameString else nameString));
+
+ /** String representation of location. */
+ final def locationString: String =
+ if (owner.isClass &&
+ (!owner.isAnonymousClass && !owner.isRefinementClass || settings.debug.value))
+ " in " + (if (owner.isModuleClass) "object " + owner.nameString else owner)
+ else "";
+
+ /** String representation of symbol's definition following its name */
+ final def infoString(tp: Type): String = {
+ def typeParamsString: String = tp match {
+ case PolyType(tparams, _) if (tparams.length != 0) =>
+ (tparams map (.defString)).mkString("[", ",", "]")
+ case _ =>
+ ""
+ }
+ if (isClass)
+ typeParamsString + " extends " + tp.resultType
+ else if (isAliasType)
+ typeParamsString + " = " + tp.resultType
+ else if (isAbstractType)
+ tp match {
+ case TypeBounds(lo, hi) =>
+ ((if (lo.symbol == AllClass) "" else " >: " + lo) +
+ (if (hi.symbol == AnyClass) "" else " <: " + hi))
+ case _ =>
+ "<: " + tp;
+ }
+ else if (isModule)
+ moduleClass.infoString(tp)
+ else
+ tp match {
+ case PolyType(tparams, res) =>
+ typeParamsString + infoString(res)
+ case MethodType(pts, res) =>
+ pts.mkString("(", ",", ")") + infoString(res)
+ case _ =>
+ ": " + tp
+ }
+ }
+
+ def infosString = infos.toString();
+
+ /** String representation of symbol's variance */
+ private def varianceString: String =
+ if (variance == 1) "+"
+ else if (variance == -1) "-"
+ else "";
+
+ /** String representation of symbol's definition */
+ final def defString: String =
+ compose(List(flagsToString(if (settings.debug.value) flags else flags & ExplicitFlags),
+ keyString,
+ varianceString + nameString + infoString(rawInfo)));
+
+ /** Concatenate strings separated by spaces */
+ private def compose(ss: List[String]): String =
+ ss.filter("" !=).mkString("", " ", "");
+ }
+
+ /** A class for term symbols */
+ class TermSymbol(initOwner: Symbol, initPos: int, initName: Name) extends Symbol(initOwner, initPos, initName) {
+ override def isTerm = true;
+
+ protected var referenced: Symbol = NoSymbol;
+
+ def cloneSymbolImpl(owner: Symbol): Symbol = {
+ val clone = new TermSymbol(owner, pos, name);
+ clone.referenced = referenced;
+ clone
+ }
+
+ override def alias: Symbol =
+ if (hasFlag(SUPERACCESSOR | PARAMACCESSOR | MIXEDIN)) initialize.referenced else NoSymbol;
+
+ def setAlias(alias: Symbol): TermSymbol = {
+ assert(alias != NoSymbol);
+ assert(hasFlag(SUPERACCESSOR | PARAMACCESSOR | MIXEDIN));
+ referenced = alias;
+ this
+ }
+
+ override def moduleClass: Symbol =
+ if (hasFlag(MODULE)) referenced else NoSymbol;
+
+ def setModuleClass(clazz: Symbol): TermSymbol = {
+ assert(hasFlag(MODULE));
+ referenced = clazz;
+ this
+ }
+ }
+
+ /** A class for term symbols */
+ class ModuleSymbol(initOwner: Symbol, initPos: int, initName: Name) extends TermSymbol(initOwner, initPos, initName) {
+
+ private var flatname = nme.EMPTY;
+
+ override def owner: Symbol =
+ if (phase.flatClasses && !hasFlag(METHOD) &&
+ rawowner != NoSymbol && !rawowner.isPackageClass) rawowner.owner
+ else rawowner;
+
+ override def name: Name =
+ if (phase.flatClasses && !hasFlag(METHOD) &&
+ rawowner != NoSymbol && !rawowner.isPackageClass) {
+ if (flatname == nme.EMPTY) {
+ assert(rawowner.isClass);
+ flatname = newTermName(rawowner.name.toString() + "$" + rawname);
+ }
+ flatname
+ } else rawname;
+
+ override def cloneSymbolImpl(owner: Symbol): Symbol = {
+ val clone = new ModuleSymbol(owner, pos, name);
+ clone.referenced = referenced;
+ clone
+ }
+ }
+
+ /** A class for type parameters viewed from inside their scopes */
+ class ThisSkolem(initOwner: Symbol, initPos: int, initName: Name, clazz: Symbol) extends TermSymbol(initOwner, initPos, initName) {
+ override def deSkolemize = clazz;
+ override def cloneSymbolImpl(owner: Symbol): Symbol = {
+ throw new Error("should not clone a this skolem");
+ }
+ override def nameString: String = clazz.name.toString() + ".this";
+ }
+
+ /** A class of type symbols. Alias and abstract types are direct instances
+ * of this class. Classes are instances of a subclass.
+ */
+ class TypeSymbol(initOwner: Symbol, initPos: int, initName: Name) extends Symbol(initOwner, initPos, initName) {
+ override def isType = true;
+ private var tyconCache: Type = null;
+ private var tyconRun: CompilerRun = null;
+ private var tpeCache: Type = _;
+ private var tpePhase: Phase = null;
+ override def tpe: Type = {
+ if (tpeCache eq NoType) throw CyclicReference(this, typeConstructor);
+ if (tpePhase != phase) {
+ if (isValid(tpePhase)) {
+ tpePhase = phase
+ } else {
+ if (isInitialized) tpePhase = phase;
+ tpeCache = NoType;
+ val targs = if (phase.erasedTypes && this != ArrayClass) List()
+ else unsafeTypeParams map (.tpe);
+ tpeCache = typeRef(if (isTypeParameterOrSkolem) NoPrefix else owner.thisType, this, targs)
+ }
+ }
+ assert(tpeCache != null/*, "" + this + " " + phase*/);//debug
+ tpeCache
+ }
+
+ override def typeConstructor: Type = {
+ if (tyconCache == null || tyconRun != currentRun) {
+ tyconCache = typeRef(if (isTypeParameter) NoPrefix else owner.thisType, this, List());
+ tyconRun = currentRun;
+ }
+ assert(tyconCache != null);
+ tyconCache
+ }
+
+ override def setInfo(tp: Type): this.type = {
+ tpePhase = null;
+ tyconCache = null;
+ tp match { //debug
+ case TypeRef(_, sym, _) =>
+ assert(sym != this, this);
+ case _ =>
+ }
+ super.setInfo(tp);
+ this
+ }
+
+ override def reset(completer: Type): unit = {
+ super.reset(completer);
+ tpePhase = null;
+ tyconCache = null;
+ }
+
+ def cloneSymbolImpl(owner: Symbol): Symbol =
+ new TypeSymbol(owner, pos, name);
+
+ if (util.Statistics.enabled) typeSymbolCount = typeSymbolCount + 1;
+ }
+
+ /** A class for type parameters viewed from inside their scopes */
+ class TypeSkolem(initOwner: Symbol, initPos: int, initName: Name, typeParam: Symbol) extends TypeSymbol(initOwner, initPos, initName) {
+ override def deSkolemize = typeParam;
+ override def cloneSymbolImpl(owner: Symbol): Symbol = {
+ throw new Error("should not clone a type skolem");
+ }
+ override def nameString: String = super.nameString + "&";
+ }
+
+ /** A class for class symbols */
+ class ClassSymbol(initOwner: Symbol, initPos: int, initName: Name) extends TypeSymbol(initOwner, initPos, initName) {
+
+
+ var sourceFile: AbstractFile = null;
+ private var thissym: Symbol = this;
+ override def isClass: boolean = true;
+ override def reset(completer: Type): unit = {
+ super.reset(completer);
+ thissym = this;
+ }
+
+ private var flatname = nme.EMPTY;
+
+ override def owner: Symbol =
+ if (phase.flatClasses && rawowner != NoSymbol && !rawowner.isPackageClass) rawowner.owner
+ else rawowner;
+
+ override def name: Name =
+ if (phase.flatClasses && rawowner != NoSymbol && !rawowner.isPackageClass) {
+ if (flatname == nme.EMPTY) {
+ assert(rawowner.isClass);
+ flatname = newTypeName(rawowner.name.toString() + "$" + rawname);
+ }
+ flatname
+ } else rawname;
+
+ private var thisTypeCache: Type = _;
+ private var thisTypePhase: Phase = null;
+
+ /** the type this.type in this class */
+ override def thisType: Type = {
+ val p = thisTypePhase;
+ if (p != phase) {
+ thisTypePhase = phase;
+ if (!(isValid(p) /*||
+ thisTypePhase != null && thisTypePhase.erasedTypes && phase.erasedTypes*/)) {
+ thisTypeCache = ThisType(this)
+/*
+ if (isModuleClass && !isRoot && !phase.erasedTypes)
+ singleType(owner.thisType, sourceModule);
+ else ThisType(this);
+*/
+ }
+ }
+ thisTypeCache
+ }
+
+ /** A symbol carrying the self type of the class as its type */
+ override def thisSym: Symbol = thissym;
+
+ /** Sets the self type of the class */
+ override def typeOfThis_=(tp: Type): unit =
+ thissym = newThisSym(pos).setInfo(tp);
+
+ override def cloneSymbolImpl(owner: Symbol): Symbol = {
+ assert(!isModuleClass);
+ val clone = new ClassSymbol(owner, pos, name);
+ if (thisSym != this) clone.typeOfThis = typeOfThis;
+ clone
+ }
+
+ override def sourceModule = if (isModuleClass) linkedModule else NoSymbol;
+
+ if (util.Statistics.enabled) classSymbolCount = classSymbolCount + 1;
+ }
+
+ /** A class for module class symbols
+ * Note: Not all module classes are of this type; when unpickled, we get plain class symbols!
+ */
+ class ModuleClassSymbol(owner: Symbol, pos: int, name: Name) extends ClassSymbol(owner, pos, name) {
+ private var module: Symbol = null;
+ def this(module: TermSymbol) = {
+ this(module.owner, module.pos, module.name.toTypeName);
+ setFlag(module.getFlag(ModuleToClassFlags) | MODULE | FINAL);
+ setSourceModule(module);
+ }
+ override def sourceModule = module;
+ def setSourceModule(module: Symbol): unit = this.module = module
+ }
+
+ /** An object repreesenting a missing symbol */
+ object NoSymbol extends Symbol(null, Position.NOPOS, nme.NOSYMBOL) {
+ setInfo(NoType);
+ override def setInfo(info: Type): this.type = { assert(info eq NoType); super.setInfo(info) }
+ override def enclClass: Symbol = this;
+ override def toplevelClass: Symbol = this;
+ override def enclMethod: Symbol = this;
+ override def owner: Symbol = throw new Error();
+ override def ownerChain: List[Symbol] = List();
+ override def alternatives: List[Symbol] = List();
+ override def reset(completer: Type): unit = {}
+ def cloneSymbolImpl(owner: Symbol): Symbol = throw new Error();
+ }
+
+ def cloneSymbols(syms: List[Symbol]): List[Symbol] = {
+ val syms1 = syms map (.cloneSymbol);
+ for (val sym1 <- syms1) sym1.setInfo(sym1.info.substSym(syms, syms1));
+ syms1
+ }
+
+ def cloneSymbols(syms: List[Symbol], owner: Symbol): List[Symbol] = {
+ val syms1 = syms map (.cloneSymbol(owner));
+ for (val sym1 <- syms1) sym1.setInfo(sym1.info.substSym(syms, syms1));
+ syms1
+ }
+
+ /** An exception for cyclic references of symbol definitions */
+ case class CyclicReference(sym: Symbol, info: Type) extends TypeError("illegal cyclic reference involving " + sym);
+
+ /** A class for type histories */
+ private case class TypeHistory(start: Phase#Id, info: Type, prev: TypeHistory) {
+ assert(prev == null || start > prev.start, this);
+ assert(start != 0);
+ override def toString() = "TypeHistory(" + phaseWithId(start) + "," + info + "," + prev + ")";
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
new file mode 100644
index 0000000000..583ca6503c
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -0,0 +1,2060 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.symtab;
+
+import scala.tools.nsc.util.Position;
+import nsc.util.{ListBuffer, HashSet};
+import Flags._;
+
+/* A standard type pattern match:
+ case ErrorType =>
+ case WildcardType =>
+ case NoType =>
+ case NoPrefix =>
+ case ThisType(_) =>
+ case SingleType(pre, sym) =>
+ case ConstantType(value) =>
+ case TypeRef(pre, sym, args) =>
+ case TypeBounds(lo, hi) =>
+ case RefinedType(parents, defs) =>
+ case ClassInfoType(parents, defs, clazz) =>
+ case MethodType(paramtypes, result) =>
+ case PolyType(tparams, result) =>
+ // the last three types are not used after phase `typer'.
+ case OverloadedType(pre, tparams, alts) =>
+ case AntiPolyType(pre: Type, targs) =>
+ case TypeVar(_, _) =>
+*/
+
+[_trait_] abstract class Types: SymbolTable {
+ import definitions._;
+
+ //statistics
+ var singletonClosureCount = 0;
+ var compoundClosureCount = 0;
+ var typerefClosureCount = 0;
+ var findMemberCount = 0;
+ var noMemberCount = 0;
+ var multMemberCount = 0;
+ var findMemberMillis = 0l;
+ var subtypeCount = 0;
+ var subtypeMillis = 0l;
+
+ private var explainSwitch = false;
+ private var checkMalformedSwitch = true;
+
+ val emptyTypeArray = new Array[Type](0);
+
+ /** The base class for all types */
+ abstract class Type {
+
+ /** Types for which asSeenFrom always is the identity, no matter what prefix or owner */
+ def isTrivial: boolean = false;
+
+ /** The symbol associated with the type */
+ def symbol: Symbol = NoSymbol;
+
+ /** The base type underlying a singleton type,
+ * identity on all other types */
+ def singleDeref: Type = this;
+
+ /** Widen from singleton type to its underlying non-singleton base type
+ * by applying one or more singleDeref steps,
+ * identity for all other types */
+ def widen: Type = this;
+
+ /** The type of `this' of a class type or reference type
+ */
+ def typeOfThis = symbol.typeOfThis;
+
+ /** Map to a this type which is a subtype of this type.
+ */
+ def narrow: Type =
+ if (phase.erasedTypes) this
+ else refinedType(List(this), commonOwner(this), EmptyScope).narrow;
+
+ /** Map a constant type to its underlying base type,
+ * identity for all other types */
+ def deconst: Type = this;
+
+ /** For a TypeBounds type, itself;
+ * for a reference denoting an abstract type, its bounds,
+ * for all other types, a TypeBounds type all of whose bounds are this type.
+ * error for all other types */
+ def bounds: TypeBounds = TypeBounds(this, this);
+
+ /** For a class or intersection type, its parents.
+ * For a TypeBounds type, the parents of its hi bound.
+ * inherited by typerefs, singleton types, and refinement types,
+ * The empty list for all other types */
+ def parents: List[Type] = List();
+
+ /** For a typeref or single-type, its prefix. NoType for all other types. */
+ def prefix: Type = NoType;
+
+ /** For a typeref, its arguments. The empty list for all other types */
+ def typeArgs: List[Type] = List();
+
+ /** For a method or poly type, its direct result type,
+ * the type itself for all other types */
+ def resultType: Type = this;
+
+ /** For a curried method or poly type its non-method result type,
+ * the type itself for all other types */
+ def finalResultType: Type = this;
+
+ /** For a method or poly type, the number of its value parameter sections,
+ * 0 for all other types */
+ def paramSectionCount: int = 0;
+
+ /** For a method or poly type, the types of its first value parameter section,
+ * the empty list for all other types */
+ def paramTypes: List[Type] = List();
+
+ /** For a poly type, its type parameters,
+ * the empty list for all other types */
+ def typeParams: List[Symbol] = List();
+
+ /** Is this type produced as a repair for an error? */
+ def isError: boolean = symbol.isError;
+
+ /** Does this type denote a stable reference (i.e. singleton type)? */
+ def isStable: boolean = false;
+
+ /** For a classtype or refined type, its defined or declared members;
+ * inherited by subtypes and typerefs.
+ * The empty scope for all other types */
+ def decls: Scope = EmptyScope;
+
+ /** The defined or declared members with name `name' in this type;
+ * an OverloadedSymbol if several exist, NoSymbol if none exist.
+ * Alternatives of overloaded symbol appear in the order they are declared.
+ */
+ def decl(name: Name): Symbol = findDecl(name, 0);
+
+ /** The non-private defined or declared members with name `name' in this type;
+ * an OverloadedSymbol if several exist, NoSymbol if none exist.
+ * Alternatives of overloaded symbol appear in the order they are declared.
+ */
+ def nonPrivateDecl(name: Name): Symbol = findDecl(name, PRIVATE);
+
+ /** A list of all members of this type (defined or inherited)
+ * Members appear in linearization order of their owners.
+ * Members with the same owner appear in reverse order of their declarations.
+ */
+ def members: List[Symbol] = findMember(nme.ANYNAME, 0, 0).alternatives;
+
+ /** A list of all non-private members of this type (defined or inherited) */
+ def nonPrivateMembers: List[Symbol] = findMember(nme.ANYNAME, PRIVATE | BRIDGE, 0).alternatives;
+
+ /** A list of all implicit symbols of this type (defined or inherited) */
+ def implicitMembers: List[Symbol] = findMember(nme.ANYNAME, BRIDGE, IMPLICIT).alternatives;
+
+ /** The member with given name,
+ * an OverloadedSymbol if several exist, NoSymbol if none exist */
+ def member(name: Name): Symbol = findMember(name, BRIDGE, 0);
+
+ /** The non-private member with given name,
+ * an OverloadedSymbol if several exist, NoSymbol if none exist */
+ def nonPrivateMember(name: Name): Symbol = findMember(name, PRIVATE | BRIDGE, 0);
+
+ /** The non-local member with given name,
+ * an OverloadedSymbol if several exist, NoSymbol if none exist */
+ def nonLocalMember(name: Name): Symbol = findMember(name, LOCAL | BRIDGE, 0);
+
+ /** The least type instance of given class which is a supertype
+ * of this type */
+ def baseType(clazz: Symbol): Type = NoType;
+
+ /** This type as seen from prefix `
+ pre' and class `clazz'. This means:
+ * Replace all thistypes of `clazz' or one of its subclasses by `pre'
+ * and instantiate all parameters by arguments of `pre'.
+ * Proceed analogously for thistypes referring to outer classes. */
+ def asSeenFrom(pre: Type, clazz: Symbol): Type =
+ if (!isTrivial && (!phase.erasedTypes || pre.symbol == ArrayClass)) {
+ new AsSeenFromMap(pre, clazz) apply this;
+ } else this;
+
+ /** The info of `sym', seen as a member of this type. */
+ def memberInfo(sym: Symbol): Type =
+ sym.info.asSeenFrom(this, sym.owner);
+
+ /** The type of `sym', seen as a memeber of this type. */
+ def memberType(sym: Symbol): Type = {
+ val result = sym.tpe.asSeenFrom(this, sym.owner);
+ /*System.out.println("" + this + ".memberType(" + sym + ") = " + result);*/
+ result
+ }
+
+ /** Substitute types `to' for occurrences of references to symbols `from'
+ * in this type. */
+ def subst(from: List[Symbol], to: List[Type]): Type =
+ new SubstTypeMap(from, to) apply this;
+
+ /** Substitute symbols `to' for occurrences of symbols `from' in this type. */
+ def substSym(from: List[Symbol], to: List[Symbol]): Type =
+ new SubstSymMap(from, to) apply this;
+
+ /** Substitute all occurrences of ThisType(from) in this type by `to' */
+ def substThis(from: Symbol, to: Type): Type =
+ new SubstThisMap(from, to) apply this;
+
+ def substSuper(from: Type, to: Type): Type =
+ new SubstSuperMap(from, to) apply this;
+
+ /** Does this type contain a reference to this symbol? */
+ def contains(sym: Symbol): boolean =
+ new ContainsTraverser(sym).traverse(this).result;
+
+ /** Is this type a subtype of that type? */
+ def <:<(that: Type): boolean = {
+ if (util.Statistics.enabled) subtypeCount = subtypeCount + 1;
+ val startTime = if (util.Statistics.enabled) System.currentTimeMillis() else 0l;
+ val result =
+ ((this eq that) ||
+ (if (explainSwitch) explain("<", isSubType, this, that) else isSubType(this, that)));
+ if (util.Statistics.enabled) subtypeMillis = subtypeMillis + System.currentTimeMillis() - startTime;
+ result
+ }
+
+ /** Is this type equivalent to that type? */
+ def =:=(that: Type): boolean = (
+ (this eq that) ||
+ (if (explainSwitch) explain("=", isSameType, this, that) else isSameType(this, that))
+ );
+
+ /** Does this type implement symbol `sym' with same or stronger type? */
+ def specializes(sym: Symbol): boolean =
+ if (explainSwitch) explain("specializes", specializesSym, this, sym)
+ else specializesSym(this, sym);
+
+ /** Is this type close enough to that type so that
+ * members with the two type would override each other?
+ * This means:
+ * - Either both types are polytypes with the same number of
+ * type parameters and their result types match after renaming
+ * corresponding type parameters
+ * - Or both types are method types with equivalent type parameter types
+ * and matching result types
+ * - Or both types are equivalent
+ * - Or phase.erasedTypes is false and both types are neither method nor
+ * poly types.
+ */
+ def matches(that: Type): boolean = matchesType(this, that);
+
+ /** The shortest sorted upwards closed array of types that contains
+ * this type as first element.
+ *
+ * A list or array of types ts is upwards closed if
+ *
+ * for all t in ts:
+ * for all typerefs p.s[args] such that t <: p.s[args]
+ * there exists a typeref p'.s[args'] in ts such that
+ * t <: p'.s['args] <: p.s[args],
+ * and
+ * for all singleton types p.s such that t <: p.s
+ * there exists a singleton type p'.s in ts such that
+ * t <: p'.s <: p.s
+ *
+ * Sorting is with respect to Symbol.isLess() on type symbols.
+ */
+ def closure: Array[Type] = Predef.Array(this);
+
+ def baseClasses: List[Symbol] = List();
+
+ /** The index of given class symbol in the closure of this type,
+ * or -1 if no base type with given class symbol exists */
+ def closurePos(sym: Symbol): int = {
+ val cl = closure;
+ var lo = 0;
+ var hi = cl.length - 1;
+ while (lo <= hi) {
+ val mid = (lo + hi) / 2;
+ val clsym = cl(mid).symbol;
+ if (sym == clsym) return mid
+ else if (sym isLess clsym) hi = mid - 1
+ else if (clsym isLess sym) lo = mid + 1
+ else throw new Error()
+ }
+ -1
+ }
+
+ /** If this is a polytype, a copy with cloned type parameters owned
+ * by `owner'. Identity for all other types. */
+ def cloneInfo(owner: Symbol) = this;
+
+ /** The string representation of this type used as a prefix */
+ def prefixString = toString() + "#";
+
+ /** The string representation of this type, with singletypes explained */
+ def toLongString = {
+ val str = toString();
+ if (str.endsWith(".type")) str + " (with underlying type " + widen + ")";
+ else str
+ }
+
+ /** Is this type completed (i.e. not a lazy type)?
+ */
+ def isComplete: boolean = true;
+
+ /** If this is a lazy type, assign a new type to `sym'. */
+ def complete(sym: Symbol): unit = {
+ if (sym == NoSymbol || sym.isPackageClass) sym.validForRun = currentRun
+ else {
+ val this1 = adaptToNewRunMap(this);
+ if (this1 eq this) sym.validForRun = currentRun
+ else {
+ //System.out.println("new type of " + sym + "=" + this1);//DEBUG
+ sym.setInfo(this1);
+ }
+ }
+ }
+
+ /** If this is a symbol loader type, load and assign a new type to `sym'. */
+ def load(sym: Symbol): unit = {}
+
+ private def findDecl(name: Name, excludedFlags: int): Symbol = {
+ var alts: List[Symbol] = List();
+ var sym: Symbol = NoSymbol;
+ var e: ScopeEntry = decls.lookupEntry(name);
+ while (e != null) {
+ if (!e.sym.hasFlag(excludedFlags)) {
+ if (sym == NoSymbol) sym = e.sym
+ else {
+ if (alts.isEmpty) alts = List(sym);
+ alts = e.sym :: alts
+ }
+ }
+ e = decls.lookupNextEntry(e)
+ }
+ if (alts.isEmpty) sym
+ else baseClasses.head.newOverloaded(this, alts)
+ }
+
+ //todo: use narrow only for modules? (correct? efficiency gain?)
+ def findMember(name: Name, excludedFlags: int, requiredFlags: int): Symbol = {
+ if (util.Statistics.enabled) findMemberCount = findMemberCount + 1;
+ val startTime = if (util.Statistics.enabled) System.currentTimeMillis() else 0l;
+
+ //System.out.println("find member " + name.decode + " in " + this + ":" + this.baseClasses);//DEBUG
+ var members: Scope = null;
+ var member: Symbol = NoSymbol;
+ var excluded = excludedFlags | DEFERRED;
+ var self: Type = null;
+ var continue = true;
+ var savedCheckMalformedSwitch = checkMalformedSwitch;
+ checkMalformedSwitch = false;
+ while (continue) {
+ continue = false;
+ var bcs = baseClasses;
+ while (!bcs.isEmpty) {
+ val decls = bcs.head.info.decls;
+ bcs = if (name == nme.CONSTRUCTOR) Nil else bcs.tail;
+ var entry = if (name == nme.ANYNAME) decls.elems else decls lookupEntry name;
+ while (entry != null) {
+ val sym = entry.sym;
+ if (sym.getFlag(requiredFlags) == requiredFlags) {
+ val excl = sym.getFlag(excluded);
+ if (excl == 0) {
+ if (name.isTypeName) {
+ checkMalformedSwitch = savedCheckMalformedSwitch;
+ if (util.Statistics.enabled) findMemberMillis = findMemberMillis + System.currentTimeMillis() - startTime;
+ return sym
+ } else if (member == NoSymbol) {
+ member = sym
+ } else if (members == null) {
+ if (member.name != sym.name ||
+ member != sym &&
+ (member.owner == sym.owner || {
+ if (self == null) self = this.narrow;
+ !self.memberType(member).matches(self.memberType(sym))}))
+ members = new Scope(List(member, sym));
+ } else {
+ var prevEntry = members lookupEntry sym.name;
+ while (prevEntry != null &&
+ !(prevEntry.sym == sym
+ ||
+ prevEntry.sym.owner != sym.owner &&
+ !prevEntry.sym.hasFlag(PRIVATE) &&
+ !sym.hasFlag(PRIVATE) && {
+ if (self == null) self = this.narrow;
+ (self.memberType(prevEntry.sym) matches self.memberType(sym))}))
+ prevEntry = members lookupNextEntry prevEntry;
+ if (prevEntry == null) {
+ members enter sym;
+ }
+ }
+ } else if (excl == DEFERRED) {
+ continue = true;
+ }
+ }
+ entry = if (name == nme.ANYNAME) entry.next else decls lookupNextEntry entry
+ } // while (entry != null)
+ // excluded = excluded | LOCAL
+ } // while (!bcs.isEmpty)
+ excluded = excludedFlags
+ } // while (continue)
+ checkMalformedSwitch = savedCheckMalformedSwitch;
+ if (util.Statistics.enabled) findMemberMillis = findMemberMillis + System.currentTimeMillis() - startTime;
+ if (members == null) {
+ if (util.Statistics.enabled) if (member == NoSymbol) noMemberCount = noMemberCount + 1;
+ member
+ } else {
+ if (util.Statistics.enabled) multMemberCount = multMemberCount + 1;
+ baseClasses.head.newOverloaded(this, members.toList)
+ }
+ }
+ }
+
+// Subclasses ------------------------------------------------------------
+
+ [_trait_] abstract class UniqueType {
+ private val hashcode = { val h = super.hashCode(); if (h < 0) -h else h }
+ override def hashCode() = hashcode;
+ }
+
+ /** A base class for types that defer some operations
+ * to their immediate supertype
+ */
+ abstract class SubType extends Type {
+ def supertype: Type;
+ override def parents: List[Type] = supertype.parents;
+ override def decls: Scope = supertype.decls;
+ override def baseType(clazz: Symbol): Type = supertype.baseType(clazz);
+ override def closure: Array[Type] = supertype.closure;
+ override def baseClasses: List[Symbol] = supertype.baseClasses;
+ }
+
+ /** A base class for types that represent a single value
+ * (single-types and this-types)
+ */
+ abstract class SingletonType extends SubType {
+ override def singleDeref: Type;
+ def supertype: Type = singleDeref;
+ override def isStable: boolean = true;
+ override def widen: Type = singleDeref.widen;
+ override def closure: Array[Type] = {
+ if (util.Statistics.enabled) singletonClosureCount = singletonClosureCount + 1;
+ addClosure(this, supertype.closure);
+ }
+ override def toString(): String = prefixString + "type";
+ }
+
+ /** An object representing an erroneous type */
+ case object ErrorType extends Type {
+ // todo see whether we can do without
+ override def isError: boolean = true;
+ override def decls: Scope = new ErrorScope(NoSymbol);
+ override def findMember(name: Name, excludedFlags: int, requiredFlags: int): Symbol = {
+ var sym = decls lookup name;
+ if (sym == NoSymbol) {
+ sym = NoSymbol.newErrorSymbol(name);
+ decls enter sym
+ }
+ sym
+ }
+ override def baseType(clazz: Symbol): Type = this;
+ override def toString(): String = "<error>";
+ override def narrow: Type = this;
+ }
+
+ /** An object representing an unknown type */
+ case object WildcardType extends Type {
+ override def toString(): String = "?"
+ }
+
+ /** An object representing a non-existing type */
+ case object NoType extends Type {
+ override def isTrivial: boolean = true;
+ override def toString(): String = "<notype>"
+ }
+
+ /** An object representing a non-existing prefix */
+ case object NoPrefix extends Type {
+ override def isTrivial: boolean = true;
+ override def isStable: boolean = true;
+ override def prefixString = "";
+ override def toString(): String = "<noprefix>";
+ }
+
+ /** A class for this-types of the form <sym>.this.type
+ */
+ abstract case class ThisType(sym: Symbol) extends SingletonType {
+ //assert(sym.isClass && !sym.isModuleClass || sym.isRoot, sym);
+ override def isTrivial: boolean = sym.isPackageClass;
+ override def symbol = sym;
+ override def singleDeref: Type = sym.typeOfThis;
+ override def prefixString =
+ if (settings.debug.value) sym.nameString + ".this.";
+ else if (sym.isRoot || sym.isEmptyPackageClass) ""
+ else if (sym.isAnonymousClass || sym.isRefinementClass) "this."
+ else if (sym.isPackageClass) sym.fullNameString + "."
+ else sym.nameString + ".this.";
+ override def narrow: Type = this;
+ }
+
+ /** A class for singleton types of the form <prefix>.<sym.name>.type.
+ * Cannot be created directly; one should always use
+ * `singleType' for creation.
+ */
+ abstract case class SingleType(pre: Type, sym: Symbol) extends SingletonType {
+ override val isTrivial: boolean = pre.isTrivial;
+ private var singleDerefCache: Type = _;
+ private var singleDerefPhase: Phase = null;
+ override def singleDeref: Type = {
+ val p = singleDerefPhase;
+ if (p != phase) {
+ singleDerefPhase = phase;
+ if (!isValid(p)) {
+ singleDerefCache = pre.memberType(sym).resultType;
+ }
+ }
+ singleDerefCache
+ }
+ override def symbol = sym;
+ override def prefix: Type = pre;
+ override def prefixString: String =
+ if (sym.isEmptyPackage && !settings.debug.value) ""
+ else pre.prefixString + sym.nameString + ".";
+ }
+
+ abstract case class SuperType(thistpe: Type, supertp: Type) extends SingletonType {
+ override val isTrivial: boolean = thistpe.isTrivial && supertp.isTrivial;
+ override def symbol = thistpe.symbol;
+ override def singleDeref = supertp;
+ override def prefix: Type = supertp.prefix;
+ override def prefixString =
+ if (thistpe.prefixString.endsWith("this."))
+ thistpe.prefixString.substring(0, thistpe.prefixString.length() - 5) + "super."
+ else thistpe.prefixString;
+ override def narrow: Type = thistpe.narrow
+ }
+
+ /** A class for the bounds of abstract types and type parameters
+ */
+ abstract case class TypeBounds(lo: Type, hi: Type) extends SubType {
+ override val isTrivial: boolean = lo.isTrivial && hi.isTrivial;
+ def supertype: Type = hi;
+ override def bounds: TypeBounds = this;
+ def containsType(that: Type) = that <:< this || lo <:< that && that <:< hi;
+ override def toString() = ">: " + lo + " <: " + hi;
+ }
+
+ /** A common base class for intersection types and class types
+ */
+ abstract class CompoundType extends Type {
+ assert(!parents.exists (.isInstanceOf[TypeBounds]), this);//debug
+
+ private var closureCache: Array[Type] = _;
+ private var closurePhase: Phase = null;
+ private var baseClassesCache: List[Symbol] = _;
+ private var baseClassesPhase: Phase = null;
+
+ override def closure: Array[Type] = {
+ def computeClosure: Array[Type] =
+ try {
+ if (util.Statistics.enabled) compoundClosureCount = compoundClosureCount + 1;
+ //System.out.println("computing closure of " + symbol.tpe + " " + parents);//DEBUG
+ val buf = new ListBuffer[Type];
+ buf += symbol.tpe;
+ var clSize = 1;
+ val nparents = parents.length;
+ if (nparents != 0) {
+ val pclosure = new Array[Array[Type]](nparents);
+ val index = new Array[int](nparents);
+ var i = 0;
+ for (val p <- parents) {
+ pclosure(i) = p.closure;
+ index(i) = 0;
+ i = i + 1
+ }
+ def nextBaseType(i: int): Type = {
+ val j = index(i);
+ val pci = pclosure(i);
+ if (j < pci.length) pci(j) else AnyClass.tpe
+ }
+ val limit = pclosure(0).length;
+ while (index(0) != limit) {
+ var minSym: Symbol = nextBaseType(0).symbol;
+ i = 1;
+ while (i < nparents) {
+ if (nextBaseType(i).symbol isLess minSym) minSym = nextBaseType(i).symbol;
+ i = i + 1
+ }
+ var minTypes: List[Type] = List();
+ i = 0;
+ while (i < nparents) {
+ val tp = nextBaseType(i);
+ if (tp.symbol == minSym) {
+ if (!(minTypes exists (tp =:=))) minTypes = tp :: minTypes;
+ index(i) = index(i) + 1
+ }
+ i = i + 1
+ }
+ buf += intersectionType(minTypes);
+ clSize = clSize + 1;
+ }
+ }
+ closureCache = new Array[Type](clSize);
+ buf.copyToArray(closureCache, 0);
+ //System.out.println("closureCache of " + symbol.tpe + " = " + List.fromArray(closureCache));//DEBUG
+ var j = 0;
+ while (j < clSize) {
+ closureCache(j) match {
+ case RefinedType(parents, decls) =>
+ assert(decls.isEmpty);
+ closureCache(j) = glb(parents)
+ case _ =>
+ }
+ j = j + 1
+ }
+ //System.out.println("closure of " + symbol.tpe + " = " + List.fromArray(closureCache));//DEBUG
+ closureCache
+ } catch {
+ case ex: MalformedClosure =>
+ throw new MalformedType(
+ "the type intersection " + this + " is malformed" +
+ "\n --- because ---\n" + ex.getMessage())
+ }
+ val p = closurePhase;
+ if (p != phase) {
+ closurePhase = phase;
+ if (!isValidForBaseClasses(p)) {
+ closureCache = null;
+ closureCache = computeClosure
+ }
+ //System.out.println("closure(" + symbol + ") = " + List.fromArray(closureCache));//DEBUG
+ }
+ if (closureCache == null)
+ throw new TypeError("illegal cyclic reference involving " + symbol);
+ closureCache;
+ }
+
+ override def baseClasses: List[Symbol] = {
+ def computeBaseClasses: List[Symbol] =
+ if (parents.isEmpty) List(symbol)
+ else {
+ //System.out.println("computing base classes of " + symbol + " at phase " + phase);//DEBUG
+ // optimized, since this seems to be performance critical
+ val superclazz = parents.head;
+ var mixins = parents.tail;
+ val sbcs = superclazz.baseClasses;
+ var bcs = sbcs;
+ def isNew(clazz: Symbol): boolean = (
+ superclazz.closurePos(clazz) < 0 &&
+ { var p = bcs;
+ while ((p ne sbcs) && (p.head != clazz)) p = p.tail;
+ p eq sbcs
+ }
+ );
+ while (!mixins.isEmpty) {
+ def addMixinBaseClasses(mbcs: List[Symbol]): List[Symbol] =
+ if (mbcs.isEmpty) bcs
+ else if (isNew(mbcs.head)) mbcs.head :: addMixinBaseClasses(mbcs.tail)
+ else addMixinBaseClasses(mbcs.tail);
+ bcs = addMixinBaseClasses(mixins.head.baseClasses);
+ mixins = mixins.tail
+ }
+ symbol :: bcs
+ }
+ val p = baseClassesPhase;
+ if (p != phase) {
+ baseClassesPhase = phase;
+ if (!isValidForBaseClasses(p)) {
+ baseClassesCache = null;
+ baseClassesCache = computeBaseClasses;
+ }
+ }
+ if (baseClassesCache == null)
+ throw new TypeError("illegal cyclic reference involving " + symbol);
+ baseClassesCache
+ }
+
+ override def baseType(sym: Symbol): Type = {
+ val index = closurePos(sym);
+ if (index >= 0) closure(index) else NoType;
+ }
+
+ override def narrow: Type = symbol.thisType;
+
+ override def toString(): String = (
+ parents.mkString("", " with ", "") +
+ (if (settings.debug.value || parents.isEmpty || decls.elems != null)
+ decls.mkString("{", "; ", "}") else "")
+ );
+ }
+
+ /** A class representing intersection types with refinements of the form
+ * <parents_0> with ... with <parents_n> { decls }
+ * Cannot be created directly;
+ * one should always use `refinedType' for creation.
+ */
+ abstract case class RefinedType(override val parents: List[Type],
+ override val decls: Scope) extends CompoundType;
+
+ /** A class representing a class info
+ */
+ case class ClassInfoType(override val parents: List[Type],
+ override val decls: Scope,
+ override val symbol: Symbol) extends CompoundType;
+
+ class PackageClassInfoType(decls: Scope, clazz: Symbol) extends ClassInfoType(List(), decls, clazz);
+
+ /** A class representing a constant type */
+ abstract case class ConstantType(value: Constant) extends SingletonType {
+ assert(value.tpe.symbol != UnitClass);
+ override def isTrivial: boolean = true;
+ override def symbol: Symbol = value.tpe.symbol;
+ override def singleDeref: Type = value.tpe;
+ override def deconst: Type = value.tpe;
+ override def toString(): String = value.tpe.toString() + "(" + value.stringValue + ")";
+ }
+
+ /** A class for named types of the form <prefix>.<sym.name>[args]
+ * Cannot be created directly; one should always use `typeRef' for creation.
+ */
+ abstract case class TypeRef(pre: Type, sym: Symbol, args: List[Type]) extends Type {
+ assert(!sym.isAbstractType || pre.isStable || pre.isError);
+ assert(!pre.isInstanceOf[ClassInfoType], this);
+ assert(!sym.isTypeParameterOrSkolem || pre == NoPrefix, this);
+
+ private var parentsCache: List[Type] = _;
+ private var parentsPhase: Phase = null;
+ private var closureCache: Array[Type] = _;
+ private var closurePhase: Phase = null;
+
+ override val isTrivial: boolean =
+ pre.isTrivial && !sym.isTypeParameter && args.forall(.isTrivial);
+
+ def transform(tp: Type): Type =
+ tp.asSeenFrom(pre, sym.owner).subst(sym.typeParams, args);
+
+ def transform(cl: Array[Type]): Array[Type] = {
+ val cl1 = new Array[Type](cl.length);
+ var i = 0;
+ while (i < cl.length) { cl1(i) = transform(cl(i)); i = i + 1 }
+ cl1
+ }
+
+ override def symbol = sym;
+
+ override def bounds: TypeBounds =
+ if (sym.isAbstractType) transform(sym.info.bounds).asInstanceOf[TypeBounds]
+ else super.bounds;
+
+ override def parents: List[Type] = {
+ val p = parentsPhase;
+ if (p != phase) {
+ parentsPhase = phase;
+ if (!isValidForBaseClasses(p)) {
+ parentsCache = sym.info.parents map transform
+ }
+ }
+ parentsCache
+ }
+
+ override def typeOfThis = transform(sym.typeOfThis);
+
+ override def narrow = if (sym.isModuleClass) transform(sym.thisType) else super.narrow;
+
+ override def prefix: Type = pre;
+
+ override def typeArgs: List[Type] = args;
+
+ override def typeParams: List[Symbol] =
+ if (args.isEmpty) symbol.unsafeTypeParams else List();
+
+ override def decls: Scope = {
+ sym.info match {
+ case TypeRef(_, sym1, _) =>
+ assert(sym1 != symbol, this);
+ case _ =>
+ }
+ sym.info.decls
+ }
+
+ override def baseType(clazz: Symbol): Type =
+ if (sym == clazz) this
+ else if (sym.isClass) transform(sym.info.baseType(clazz))
+ else pre.memberInfo(sym).baseType(clazz);
+
+ override def closure: Array[Type] = {
+ val p = closurePhase;
+ if (p != phase) {
+ closurePhase = phase;
+ if (!isValidForBaseClasses(p)) {
+ if (util.Statistics.enabled) typerefClosureCount = typerefClosureCount + 1;
+ closureCache =
+ if (sym.isAbstractType) addClosure(this, transform(bounds.hi).closure)
+ else transform(sym.info.closure);
+ }
+ }
+ closureCache
+ }
+
+ override def baseClasses: List[Symbol] = sym.info.baseClasses;
+
+ override def toString(): String = {
+ if (!settings.debug.value) {
+ if (sym == RepeatedParamClass && !args.isEmpty)
+ return args(0).toString() + "*";
+ if (sym == ByNameParamClass && !args.isEmpty)
+ return "=> " + args(0).toString();
+ if (isFunctionType(this))
+ return args.init.mkString("(", ", ", ")") + " => " + args.last;
+ }
+ (pre.prefixString + sym.nameString +
+ (if (args.isEmpty) "" else args.mkString("[", ",", "]")))
+ }
+
+ override def prefixString =
+ if (settings.debug.value) super.prefixString
+ else if (sym.isRoot || sym.isEmptyPackageClass ||
+ sym.isAnonymousClass || sym.isRefinementClass) ""
+ else if (sym.isPackageClass) sym.fullNameString + "."
+ else super.prefixString;
+ }
+
+ /** A class representing a method type with parameters.
+ */
+ case class MethodType(override val paramTypes: List[Type],
+ override val resultType: Type) extends Type {
+ override val isTrivial: boolean =
+ paramTypes.forall(.isTrivial) && resultType.isTrivial;
+
+ assert(paramTypes forall (pt => !pt.symbol.isImplClass));//debug
+ override def paramSectionCount: int = resultType.paramSectionCount + 1;
+
+ override def finalResultType: Type = resultType.finalResultType;
+
+ override def toString(): String = paramTypes.mkString("(", ",", ")") + resultType;
+ }
+
+ class ImplicitMethodType(pts: List[Type], rt: Type) extends MethodType(pts, rt) {
+ override def toString(): String = paramTypes.mkString("(implicit ", ",", ")") + resultType;
+ }
+
+ class JavaMethodType(pts: List[Type], rt: Type) extends MethodType(pts, rt);
+
+ /** A class representing a polymorphic type or, if tparams.length == 0,
+ * a parameterless method type.
+ */
+ case class PolyType(override val typeParams: List[Symbol], override val resultType: Type)
+ extends Type {
+
+ override def paramSectionCount: int = resultType.paramSectionCount;
+ override def paramTypes: List[Type] = resultType.paramTypes;
+
+ override def finalResultType: Type = resultType.finalResultType;
+
+ override def parents: List[Type] = resultType.parents;
+ override def decls: Scope = resultType.decls;
+ override def symbol: Symbol = resultType.symbol;
+ override def closure: Array[Type] = resultType.closure;
+ override def baseClasses: List[Symbol] = resultType.baseClasses;
+ override def baseType(clazz: Symbol): Type = resultType.baseType(clazz);
+ override def narrow: Type = resultType.narrow;
+
+ override def toString(): String =
+ (if (typeParams.isEmpty) "=> "
+ else (typeParams map (.defString)).mkString("[", ",", "]")) + resultType;
+
+ override def cloneInfo(owner: Symbol) = {
+ val tparams = cloneSymbols(typeParams, owner);
+ PolyType(tparams, resultType.substSym(typeParams, tparams))
+ }
+ }
+
+ /** A class containing the alternatives and type prefix of an overloaded symbol.
+ * Not used after phase `typer'.
+ */
+ case class OverloadedType(pre: Type, alternatives: List[Symbol]) extends Type {
+ override def prefix: Type = pre;
+ override def toString() = (alternatives map pre.memberType).mkString("", " <and> ", "")
+ }
+
+ /** A class remembering a type instantiation for some a set of overloaded polymorphic symbols.
+ * Not used after phase `typer'.
+ */
+ case class AntiPolyType(pre: Type, targs: List[Type]) extends Type {
+ override def toString() = pre.toString() + targs.mkString("(with type arguments ", ",", ")");
+ override def memberType(sym: Symbol) = pre.memberType(sym) match {
+ case PolyType(tparams, restp) => restp.subst(tparams, targs)
+ }
+ }
+
+ /** A class representing a type variable
+ * Not used after phase `typer'.
+ */
+ case class TypeVar(origin: Type, constr: TypeConstraint) extends Type {
+ override def symbol = origin.symbol;
+ override def toString(): String =
+ if (constr.inst eq NoType) "?" + origin else constr.inst.toString();
+ }
+
+ /** A class representing an as-yet unevaluated type.
+ */
+ abstract class LazyType extends Type {
+ override def isComplete: boolean = false;
+ override def complete(sym: Symbol): unit;
+ }
+
+ /** A class representing a lazy type with known type parameters
+ */
+ class LazyPolyType(override val typeParams: List[Symbol], restp: Type) extends LazyType {
+ override def complete(sym: Symbol): unit = {
+ restp.complete(sym);
+ }
+ }
+
+// Creators ---------------------------------------------------------------
+
+ /** Rebind symbol `sym' to an overriding member in type `pre' */
+ private def rebind(pre: Type, sym: Symbol): Symbol = {
+ val owner = sym.owner;
+ if (owner.isClass && owner != pre.symbol && !sym.isFinal) {
+ val rebind = pre.nonPrivateMember(sym.name).suchThat(sym => sym.isType || sym.isStable);
+ if (rebind == NoSymbol) sym else rebind
+ } else sym
+ }
+
+ /** The canonical creator for this-types */
+ def ThisType(sym: Symbol): Type =
+ if (phase.erasedTypes) sym.tpe else unique(new ThisType(sym) with UniqueType);
+
+ /** The canonical creator for single-types */
+ def singleType(pre: Type, sym: Symbol): Type = {
+ if (phase.erasedTypes)
+ sym.tpe.resultType
+ else if (checkMalformedSwitch && !pre.isStable && !pre.isError)
+ throw new MalformedType(pre, sym.name.toString())
+ else
+ unique(new SingleType(pre, rebind(pre, sym)) with UniqueType)
+ }
+
+ /** The canonical creator for super-types */
+ def SuperType(thistp: Type, supertp: Type): Type =
+ if (phase.erasedTypes) supertp
+ else unique(new SuperType(thistp, supertp) with UniqueType);
+
+ /** The canonical creator for type bounds */
+ def TypeBounds(lo: Type, hi: Type): TypeBounds =
+ unique(new TypeBounds(lo, hi) with UniqueType);
+
+ /** the canonical creator for a refined type with a given scope */
+ def refinedType(parents: List[Type], owner: Symbol, decls: Scope): Type = {
+ if (phase.erasedTypes)
+ if (parents.isEmpty) ObjectClass.tpe else parents.head
+ else {
+ val clazz = owner.newRefinementClass(Position.NOPOS);
+ val result = new RefinedType(parents, decls) { override def symbol: Symbol = clazz }
+ clazz.setInfo(result);
+ result
+ }
+ }
+
+ /** the canonical creator for a refined type with an initially empty scope */
+ def refinedType(parents: List[Type], owner: Symbol): Type =
+ refinedType(parents, owner, new Scope);
+
+ /** the canonical creator for a constant type */
+ def ConstantType(value: Constant): ConstantType =
+ unique(new ConstantType(value) with UniqueType);
+
+ /** The canonical creator for typerefs */
+ def typeRef(pre: Type, sym: Symbol, args: List[Type]): Type = {
+ val sym1 = if (sym.isAbstractType) rebind(pre, sym) else sym;
+ if (checkMalformedSwitch && sym1.isAbstractType && !pre.isStable && !pre.isError)
+ throw new MalformedType(pre, sym.nameString);
+// if (sym1.hasFlag(LOCKED))
+// throw new TypeError("illegal cyclic reference involving " + sym1);
+ if (sym1.isAliasType && sym1.info.typeParams.length == args.length) {
+ // note: we require that object is initialized,
+ // that's why we use info.typeParams instead of typeParams.
+ if (sym1.hasFlag(LOCKED))
+ throw new TypeError("illegal cyclic reference involving " + sym1);
+ sym1.setFlag(LOCKED);
+ val result = sym1.info.resultType.asSeenFrom(pre, sym1.owner).subst(sym1.typeParams, args);
+ sym1.resetFlag(LOCKED);
+ result
+ } else {
+ rawTypeRef(pre, sym1, args)
+ }
+ }
+
+ /** create a type-ref as found, without checks or rebinds */
+ def rawTypeRef(pre: Type, sym: Symbol, args: List[Type]): Type = {
+ unique(new TypeRef(pre, sym, args) with UniqueType)
+ }
+
+ /** The canonical creator for implicit method types */
+ def ImplicitMethodType(paramTypes: List[Type], resultType: Type): ImplicitMethodType =
+ new ImplicitMethodType(paramTypes, resultType); // don't unique this!
+
+ /** The canonical creator for implicit method types */
+ def JavaMethodType(paramTypes: List[Type], resultType: Type): JavaMethodType =
+ new JavaMethodType(paramTypes, resultType); // don't unique this!
+
+ /** A creator for intersection type where intersections of a single type are
+ * replaced by the type itself. */
+ def intersectionType(tps: List[Type], owner: Symbol): Type = tps match {
+ case List(tp) => tp
+ case _ => refinedType(tps, owner)
+ }
+
+ /** A creator for intersection type where intersections of a single type are
+ * replaced by the type itself. */
+ def intersectionType(tps: List[Type]): Type = tps match {
+ case List(tp) => tp
+ case _ => refinedType(tps, commonOwner(tps))
+ }
+
+ /** A creator for type applications */
+ def appliedType(tycon: Type, args: List[Type]): Type = tycon match {
+ case TypeRef(pre, sym, _) => typeRef(pre, sym, args)
+ case PolyType(tparams, restpe) => restpe.subst(tparams, args)
+ case ErrorType => tycon
+ case _ =>
+ System.out.println(tycon.getClass());
+ System.out.println(tycon.$tag());
+ throw new Error();
+ }
+
+// Hash consing --------------------------------------------------------------
+
+ private val uniques = new HashSet[AnyRef](20000);
+
+ def uniqueTypeCount = uniques.size; // for statistics
+
+ private def unique[T <: AnyRef](tp: T): T = {
+ val tp1 = uniques.findEntry(tp);
+ if (tp1 == null) {
+ uniques.addEntry(tp); tp
+ } else {
+ tp1.asInstanceOf[T]
+ }
+ }
+
+// Helper Classes ---------------------------------------------------------
+
+ /** A class expressing upper and lower bounds constraints
+ * for type variables, as well as their instantiations */
+ class TypeConstraint {
+ var lobounds: List[Type] = List();
+ var hibounds: List[Type] = List();
+ var inst: Type = NoType;
+
+ def instantiate(tp: Type): boolean =
+ if (lobounds.forall(.<:<(tp)) && hibounds.forall(tp.<:<)) {
+ inst = tp; true
+ } else false;
+ }
+
+ /** A prototype for mapping a function over all possible types
+ */
+ trait TypeMap extends Function1[Type, Type] {
+ // deferred inherited: def apply(tp: Type): Type
+
+ private def cloneDecls(result: Type, tp: Type, decls: Scope): Type = {
+ val syms1 = decls.toList;
+ for (val sym <- syms1)
+ result.decls.enter(sym.cloneSymbol(result.symbol));
+ val syms2 = result.decls.toList;
+ val resultThis = result.symbol.thisType;
+ for (val sym <- syms2)
+ sym.setInfo(sym.info.substSym(syms1, syms2).substThis(tp.symbol, resultThis));
+ result
+ }
+
+ /** Map this function over given type */
+ def mapOver(tp: Type): Type = tp match {
+ case ErrorType => tp
+ case WildcardType => tp
+ case NoType => tp
+ case NoPrefix => tp
+ case ThisType(_) => tp
+ case ConstantType(_) => tp
+ case SingleType(pre, sym) =>
+ if (sym.isPackageClass) tp // short path
+ else {
+ val pre1 = this(pre);
+ if (pre1 eq pre) tp
+ else singleType(pre1, sym)
+ }
+ case SuperType(thistp, supertp) =>
+ val thistp1 = this(thistp);
+ val supertp1 = this(supertp);
+ if ((thistp1 eq thistp) && (supertp1 eq supertp)) tp
+ else SuperType(thistp1, supertp1)
+ case TypeRef(pre, sym, args) =>
+ val pre1 = this(pre);
+ val args1 = List.mapConserve(args)(this);
+ if ((pre1 eq pre) && (args1 eq args)) tp
+ else typeRef(pre1, sym, args1)
+ case TypeBounds(lo, hi) =>
+ val lo1 = this(lo);
+ val hi1 = this(hi);
+ if ((lo1 eq lo) && (hi1 eq hi)) tp
+ else TypeBounds(lo1, hi1)
+ case RefinedType(parents, decls) =>
+ val parents1 = List.mapConserve(parents)(this);
+ val decls1 = mapOver(decls);
+ if ((parents1 eq parents) && (decls1 eq decls)) tp
+ else cloneDecls(refinedType(parents1, tp.symbol.owner), tp, decls1)
+/*
+ case ClassInfoType(parents, decls, clazz) =>
+ val parents1 = List.mapConserve(parents)(this);
+ val decls1 = mapOver(decls);
+ if ((parents1 eq parents) && (decls1 eq decls)) tp
+ else cloneDecls(ClassInfoType(parents1, new Scope(), clazz), tp, decls1)
+*/
+ case MethodType(paramtypes, result) =>
+ val paramtypes1 = List.mapConserve(paramtypes)(this);
+ val result1 = this(result);
+ if ((paramtypes1 eq paramtypes) && (result1 eq result)) tp
+ else if (tp.isInstanceOf[ImplicitMethodType]) ImplicitMethodType(paramtypes1, result1)
+ else if (tp.isInstanceOf[JavaMethodType]) JavaMethodType(paramtypes1, result1)
+ else MethodType(paramtypes1, result1)
+ case PolyType(tparams, result) =>
+ val tparams1 = mapOver(tparams);
+ var result1 = this(result);
+ if ((tparams1 eq tparams) && (result1 eq result)) tp
+ else PolyType(tparams1, result1.substSym(tparams, tparams1))
+ case OverloadedType(pre, alts) =>
+ val pre1 = if (pre.isInstanceOf[ClassInfoType]) pre else this(pre);
+ if (pre1 eq pre) tp
+ else OverloadedType(pre1, alts)
+ case AntiPolyType(pre, args) =>
+ val pre1 = this(pre);
+ val args1 = List.mapConserve(args)(this);
+ if ((pre1 eq pre) && (args1 eq args)) tp
+ else AntiPolyType(pre1, args1)
+ case TypeVar(_, constr) =>
+ if (constr.inst != NoType) this(constr.inst)
+ else tp
+ case _ =>
+ tp
+ // throw new Error("mapOver inapplicable for " + tp);
+ }
+
+ /** Map this function over given scope */
+ private def mapOver(scope: Scope): Scope = {
+ val elems = scope.toList;
+ val elems1 = mapOver(elems);
+ if (elems1 eq elems) scope
+ else new Scope(elems1)
+ }
+
+ /** Map this function over given list of symbols */
+ private def mapOver(syms: List[Symbol]): List[Symbol] = {
+ val infos = syms map (.info);
+ val infos1 = List.mapConserve(infos)(this);
+ if (infos1 eq infos) syms
+ else {
+ val syms1 = syms map (.cloneSymbol);
+ (List.map2(syms1, infos1)
+ ((sym1, info1) => sym1.setInfo(info1.substSym(syms, syms1))))
+ }
+ }
+ }
+
+ abstract class TypeTraverser extends TypeMap {
+ def traverse(tp: Type): TypeTraverser; //todo: return unit instead?
+ def apply(tp: Type): Type = { traverse(tp); tp }
+ }
+
+ /** A map to compute the asSeenFrom method */
+ class AsSeenFromMap(pre: Type, clazz: Symbol) extends TypeMap {
+ def apply(tp: Type): Type =
+ if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) tp
+ else tp match {
+ case ThisType(sym) =>
+ def toPrefix(pre: Type, clazz: Symbol): Type =
+ if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) tp
+ else if ((sym isSubClass clazz) && (pre.widen.symbol isSubClass sym)) pre
+ else toPrefix(pre.baseType(clazz).prefix, clazz.owner);
+ toPrefix(pre, clazz)
+ case TypeRef(prefix, sym, args) if (sym.isTypeParameter) =>
+ def toInstance(pre: Type, clazz: Symbol): Type =
+ if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) tp
+ else {
+ val symclazz = sym.owner;
+ def throwError =
+ throw new Error("" + tp + " in " + symclazz +
+ " cannot be instantiated from " + pre.widen);
+ def instParam(ps: List[Symbol], as: List[Type]): Type =
+ if (ps.isEmpty) throwError
+ else if (sym eq ps.head) as.head
+ else instParam(ps.tail, as.tail);
+ if (symclazz == clazz && (pre.widen.symbol isSubClass symclazz))
+ pre.baseType(symclazz) match {
+ case TypeRef(_, basesym, baseargs) =>
+ if (basesym.typeParams.length != baseargs.length)
+ assert(false, "asSeenFrom(" + pre + "," + clazz + ")" + sym + " " + basesym + " " + baseargs); //debug
+ instParam(basesym.typeParams, baseargs);
+ case _ =>
+ throwError
+ }
+ else toInstance(pre.baseType(clazz).prefix, clazz.owner)
+ }
+ toInstance(pre, clazz)
+ case _ =>
+ mapOver(tp)
+ }
+ }
+
+ /** A base class to compute all substitutions */
+ abstract class SubstMap[T](from: List[Symbol], to: List[T]) extends TypeMap {
+
+ /** Are sym1, sym1 the same. Can be tunded by subclasses */
+ protected def matches(sym: Symbol, sym1: Symbol): boolean = sym eq sym1;
+
+ /** Map target to type, can be tuned by subclasses */
+ protected def toType(fromtp: Type, t: T): Type;
+
+ def apply(tp: Type): Type = {
+ def subst(sym: Symbol, from: List[Symbol], to: List[T]): Type =
+ if (from.isEmpty) tp
+ else if (matches(from.head, sym)) toType(tp, to.head)
+ else subst(sym, from.tail, to.tail);
+ tp match {
+ case TypeRef(NoPrefix, sym, _) =>
+ subst(sym, from, to)
+ case SingleType(NoPrefix, sym) =>
+ subst(sym, from, to)
+ case PolyType(tparams, restp) =>
+ assert(!(tparams exists (from contains)));
+ mapOver(tp)
+ case _ =>
+ mapOver(tp)
+ }
+ }
+ }
+
+ /** A map to implement the substSym method */
+ class SubstSymMap(from: List[Symbol], to: List[Symbol])
+ extends SubstMap(from, to) {
+ protected def toType(fromtp: Type, sym: Symbol) = fromtp match {
+ case TypeRef(pre, _, args) => typeRef(pre, sym, args)
+ case SingleType(pre, _) => singleType(pre, sym)
+ }
+ }
+
+ /** A map to implement the subst method */
+ class SubstTypeMap(from: List[Symbol], to: List[Type])
+ extends SubstMap(from, to) {
+ protected def toType(fromtp: Type, tp: Type) = tp;
+ }
+
+ /** A map to implement the substThis method */
+ class SubstThisMap(from: Symbol, to: Type) extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case ThisType(sym) if (sym == from) => to
+ case _ => mapOver(tp)
+ }
+ }
+
+ class SubstSuperMap(from: Type, to: Type) extends TypeMap {
+ def apply(tp: Type): Type = if (tp eq from) to else mapOver(tp);
+ }
+
+ /** A map to convert every occurrence of a wildcard type to a fresh
+ * type variable */
+ object wildcardToTypeVarMap extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case WildcardType => TypeVar(tp, new TypeConstraint)
+ case _ => mapOver(tp)
+ }
+ }
+
+ /** A map to implement the contains method */
+ class ContainsTraverser(sym: Symbol) extends TypeTraverser {
+ var result = false;
+ def traverse(tp: Type): ContainsTraverser = {
+ if (!result) {
+ tp match {
+ case TypeRef(_, sym1, _) if (sym == sym1) => result = true
+ case SingleType(_, sym1) if (sym == sym1) => result = true
+ case _ => mapOver(tp)
+ }
+ }
+ this
+ }
+ }
+
+ /** A map to compute the most deeply nested owner that contains all the symbols
+ * of thistype or prefixless typerefs/singletype occurrences in given type */
+ object commonOwnerMap extends TypeMap {
+ var result: Symbol = _;
+ def init = { result = NoSymbol }
+ def apply(tp: Type): Type = {
+ tp match {
+ case ThisType(sym) =>
+ register(sym);
+ case TypeRef(NoPrefix, sym, args) =>
+ register(sym.owner); args foreach {arg => apply(arg); ()}
+ case SingleType(NoPrefix, sym) =>
+ register(sym.owner);
+ case _ =>
+ mapOver(tp)
+ }
+ tp
+ }
+ private def register(sym: Symbol): unit = {
+ while (result != NoSymbol && sym != result && !(sym isNestedIn result))
+ result = result.owner;
+ }
+ }
+
+ object adaptToNewRunMap extends TypeMap {
+ private def adaptToNewRun(pre: Type, sym: Symbol): Symbol = {
+ if (sym.isModuleClass) adaptToNewRun(pre, sym.sourceModule).moduleClass;
+ else if ((pre eq NoPrefix) || (pre eq NoType) || sym.owner.isPackageClass) sym
+ else {
+ val rebind0 = pre.member(sym.name);
+ val rebind = rebind0.suchThat(sym => sym.isType || sym.isStable);
+ if (rebind == NoSymbol) throw new MalformedType(pre, sym.name.toString());
+ rebind
+ }
+ }
+ def apply(tp: Type): Type = tp match {
+ case ThisType(sym) if (sym.isModuleClass) =>
+ val sym1 = adaptToNewRun(sym.owner.thisType, sym);
+ if (sym1 == sym) tp else ThisType(sym1)
+ case SingleType(pre, sym) =>
+ if (sym.isPackage) tp
+ else {
+ val pre1 = this(pre);
+ val sym1 = adaptToNewRun(pre1, sym);
+ if ((pre1 eq pre) && (sym1 eq sym)) tp
+ else singleType(pre1, sym1)
+ }
+ case TypeRef(pre, sym, args) =>
+ if (sym.isPackageClass) tp
+ else {
+ val pre1 = this(pre);
+ val args1 = List.mapConserve(args)(this);
+ val sym1 = adaptToNewRun(pre1, sym);
+ if ((pre1 eq pre) && (sym1 eq sym) && (args1 eq args) && sym.isExternal) tp
+ else typeRef(pre1, sym1, args1)
+ }
+ case PolyType(tparams, restp) =>
+ val restp1 = this(restp);
+ if (restp1 eq restp) tp
+ else PolyType(tparams, restp1)
+ case ClassInfoType(parents, decls, clazz) =>
+ val parents1 = List.mapConserve(parents)(this);
+ if (parents1 eq parents) tp
+ else ClassInfoType(parents1, decls, clazz)
+ case RefinedType(parents, decls) =>
+ val parents1 = List.mapConserve(parents)(this);
+ if (parents1 eq parents) tp
+ else refinedType(parents1, tp.symbol.owner, decls)
+ case SuperType(_, _) => mapOver(tp)
+ case TypeBounds(_, _) => mapOver(tp)
+ case MethodType(_, _) => mapOver(tp)
+ case TypeVar(_, _) => mapOver(tp)
+ case _ => tp
+ }
+ }
+
+ object freeTypeParams extends TypeTraverser {
+ private var result: List[Symbol] = _;
+ private def includeIfAbstract(sym: Symbol): unit = {
+ if (sym.isAbstractType && !result.contains(sym)) result = sym :: result;
+ }
+ override def traverse(tp: Type): TypeTraverser = {
+ tp match {
+ case TypeRef(NoPrefix, sym, _) =>
+ includeIfAbstract(sym)
+ case TypeRef(ThisType(_), sym, _) =>
+ includeIfAbstract(sym)
+ case _ =>
+ }
+ mapOver(tp);
+ this
+ }
+ def collect(tp: Type): List[Symbol] = {
+ result = List();
+ traverse(tp);
+ result
+ }
+ }
+
+// Helper Methods -------------------------------------------------------------
+
+ final def isValid(p: Phase): boolean =
+ p != null && phaseWithId(p.id) == p && {
+ if (phase.id > p.id) infoTransformers.nextFrom(p.id).pid >= phase.id
+ else infoTransformers.nextFrom(phase.id).pid >= p.id
+ }
+
+ final def isValidForBaseClasses(p: Phase): boolean = {
+ def noChangeInBaseClasses(it: InfoTransformer, limit: Phase#Id): boolean = (
+ it.pid >= limit ||
+ !it.changesBaseClasses && noChangeInBaseClasses(it.next, limit)
+ );
+ p != null && phaseWithId(p.id) == p && {
+ if (phase.id > p.id) noChangeInBaseClasses(infoTransformers.nextFrom(p.id), phase.id)
+ else noChangeInBaseClasses(infoTransformers.nextFrom(phase.id), p.id)
+ }
+ }
+
+ /** Do tp1 and tp2 denote equivalent types? */
+ def isSameType(tp1: Type, tp2: Type): boolean = {
+ Pair(tp1, tp2) match {
+ case Pair(ErrorType, _) => true
+ case Pair(WildcardType, _) => true
+ case Pair(_, ErrorType) => true
+ case Pair(_, WildcardType) => true
+
+ case Pair(NoType, _) => false
+ case Pair(NoPrefix, _) => tp2.symbol.isPackageClass
+ case Pair(_, NoType) => false
+ case Pair(_, NoPrefix) => tp1.symbol.isPackageClass
+
+ case Pair(ThisType(sym1), ThisType(sym2)) =>
+ sym1 == sym2
+ case Pair(SingleType(pre1, sym1), SingleType(pre2, sym2))
+ if ((sym1 == sym2) && (pre1 =:= pre2)) =>
+ true
+ case Pair(SingleType(pre1, sym1), ThisType(sym2))
+ if (sym1.isModule &&
+ sym1.moduleClass == sym2 &&
+ pre1 =:= sym2.owner.thisType) =>
+ true
+ case Pair(ThisType(sym1), SingleType(pre2, sym2))
+ if (sym2.isModule &&
+ sym2.moduleClass == sym1 &&
+ pre2 =:= sym1.owner.thisType) =>
+ true
+ case Pair(ConstantType(value1), ConstantType(value2)) =>
+ value1 == value2
+ case Pair(TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) =>
+ sym1 == sym2 && (phase.erasedTypes || pre1 =:= pre2) && isSameTypes(args1, args2)
+ case Pair(RefinedType(parents1, ref1), RefinedType(parents2, ref2)) =>
+ def isSubScope(s1: Scope, s2: Scope): boolean = s2.toList.forall {
+ sym2 =>
+ val sym1 = s1.lookup(sym2.name);
+ sym1.info =:= sym2.info.substThis(sym2.owner, sym1.owner.thisType)
+ }
+ isSameTypes(parents1, parents2) && isSubScope(ref1, ref2) && isSubScope(ref2, ref1)
+ case Pair(MethodType(pts1, res1), MethodType(pts2, res2)) =>
+ (pts1.length == pts2.length &&
+ isSameTypes(pts1, pts2) &&
+ res1 =:= res2 &&
+ tp1.isInstanceOf[ImplicitMethodType] == tp2.isInstanceOf[ImplicitMethodType])
+ case Pair(PolyType(tparams1, res1), PolyType(tparams2, res2)) =>
+ (tparams1.length == tparams2.length &&
+ List.forall2(tparams1, tparams2)
+ ((p1, p2) => p1.info =:= p2.info.substSym(tparams2, tparams1)) &&
+ res1 =:= res2.substSym(tparams2, tparams1))
+ case Pair(TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) =>
+ lo1 =:= lo2 && hi1 =:= hi2
+ case Pair(TypeVar(_, constr1), _) =>
+ if (constr1.inst != NoType) constr1.inst =:= tp2
+ else constr1 instantiate (wildcardToTypeVarMap(tp2))
+ case Pair(_, TypeVar(_, constr2)) =>
+ if (constr2.inst != NoType) tp1 =:= constr2.inst
+ else constr2 instantiate (wildcardToTypeVarMap(tp1))
+ case Pair(SingleType(_, _), _)
+ if (tp2.isStable && tp1.singleDeref =:= tp2) =>
+ true
+ case Pair(_, SingleType(_, _))
+ if (tp1.isStable && tp1 =:= tp2.singleDeref) =>
+ true
+ case _ =>
+ false
+ }
+ }
+
+ /** Are tps1 and tps2 lists of pairwise equivalent types? */
+ def isSameTypes(tps1: List[Type], tps2: List[Type]): boolean = (
+ tps1.length == tps2.length &&
+ List.forall2(tps1, tps2)((tp1, tp2) => tp1 =:= tp2)
+ );
+
+ var subtypecount = 0;
+ def isSubType(tp1: Type, tp2: Type): boolean = {
+ subtypecount = subtypecount + 1;
+ if (subtypecount == 20) throw new Error("recursive <:<");
+ val result = isSubType0(tp1, tp2);
+ subtypecount = subtypecount - 1;
+ result
+ }
+
+ /** Does tp1 conform to tp2? */
+ def isSubType0(tp1: Type, tp2: Type): boolean = {
+ Pair(tp1, tp2) match {
+ case Pair(ErrorType, _) => true
+ case Pair(WildcardType, _) => true
+ case Pair(_, ErrorType) => true
+ case Pair(_, WildcardType) => true
+
+ case Pair(NoType, _) => false
+ case Pair(NoPrefix, _) => tp2.symbol.isPackageClass
+ case Pair(_, NoType) => false
+ case Pair(_, NoPrefix) => tp1.symbol.isPackageClass
+
+ case Pair(ThisType(_), ThisType(_)) => tp1 =:= tp2
+ case Pair(ThisType(_), SingleType(_, _)) => tp1 =:= tp2
+ case Pair(SingleType(_, _), ThisType(_)) => tp1 =:= tp2
+ case Pair(SingleType(_, _), SingleType(_, _)) => tp1 =:= tp2
+ case Pair(ConstantType(_), ConstantType(_)) => tp1 =:= tp2
+
+ case Pair(TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) =>
+ //System.out.println("isSubType " + tp1 + " " + tp2);//DEBUG
+ def isSubArgs(tps1: List[Type], tps2: List[Type],
+ tparams: List[Symbol]): boolean = (
+ tps1.isEmpty && tps2.isEmpty
+ ||
+ !tps1.isEmpty && !tps2.isEmpty &&
+ (tparams.head.hasFlag(COVARIANT) || (tps2.head <:< tps1.head)) &&
+ (tparams.head.hasFlag(CONTRAVARIANT) || tps1.head <:< tps2.head) &&
+ isSubArgs(tps1.tail, tps2.tail, tparams.tail)
+ );
+ (sym1 == sym2 && (pre1 <:< pre2) && isSubArgs(args1, args2, sym1.typeParams)
+ ||
+ sym1.isAbstractType && !(tp1 =:= tp1.bounds.hi) && (tp1.bounds.hi <:< tp2)
+ ||
+ sym2.isAbstractType && !(tp2 =:= tp2.bounds.lo) && (tp1 <:< tp2.bounds.lo)
+ ||
+ sym2.isClass &&
+ ({ val base = tp1 baseType sym2; !(base eq tp1) && (base <:< tp2) })
+ ||
+ sym1 == AllClass
+ ||
+ sym1 == AllRefClass && sym2 != AllClass && tp2 <:< AnyRefClass.tpe)
+ case Pair(MethodType(pts1, res1), MethodType(pts2, res2)) =>
+ (pts1.length == pts2.length &&
+ matchingParams(pts1, pts2, tp2.isInstanceOf[JavaMethodType]) &&
+ (res1 <:< res2) &&
+ tp1.isInstanceOf[ImplicitMethodType] == tp2.isInstanceOf[ImplicitMethodType])
+ case Pair(PolyType(tparams1, res1), PolyType(tparams2, res2)) =>
+ (tparams1.length == tparams2.length &&
+ List.forall2(tparams1, tparams2)
+ ((p1, p2) => p2.info.substSym(tparams2, tparams1) <:< p1.info) &&
+ res1 <:< res2.substSym(tparams2, tparams1))
+ case Pair(TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) =>
+ lo2 <:< lo1 && hi1 <:< hi2
+ case Pair(_, TypeVar(_, constr2)) =>
+ if (constr2.inst != NoType) tp1 <:< constr2.inst
+ else { constr2.lobounds = tp1 :: constr2.lobounds; true }
+ case Pair(TypeVar(_, constr1), _) =>
+ if (constr1.inst != NoType) constr1.inst <:< tp2
+ else { constr1.hibounds = tp2 :: constr1.hibounds; true }
+ case Pair(_, RefinedType(parents2, ref2)) =>
+ (parents2 forall tp1.<:<) && (ref2.toList forall tp1.specializes)
+ case Pair(RefinedType(parents1, ref1), _) =>
+ parents1 exists (.<:<(tp2))
+ /* todo: replace following with
+ case Pair(ThisType(_), _)
+ | Pair(SingleType(_, _), _)
+ | Pair(ConstantType(_), _) =>
+ once patern matching bug is fixed */
+ case Pair(ThisType(_), _) => tp1.singleDeref <:< tp2
+ case Pair(SingleType(_, _), _) => tp1.singleDeref <:< tp2
+ case Pair(ConstantType(_), _) => tp1.singleDeref <:< tp2
+
+ case Pair(TypeRef(pre1, sym1, args1), _) =>
+ (sym1 == AllClass && tp2 <:< AnyClass.tpe
+ ||
+ sym1 == AllRefClass && tp2.symbol != AllClass && tp2 <:< AnyRefClass.tpe)
+ case _ =>
+ false
+ }
+ }
+
+ /** Are tps1 and tps2 lists of equal length such that all elements
+ * of tps1 conform to corresponding elements of tps2? */
+ def isSubTypes(tps1: List[Type], tps2: List[Type]): boolean = (
+ tps1.length == tps2.length &&
+ List.forall2(tps1, tps2)((tp1, tp2) => tp1 <:< tp2)
+ );
+
+ /** Does type `tp' implement symbol `sym' with same or stronger type?
+ * Exact only if `sym' is a member of some refinement type, otherwise
+ * we might return false negatives */
+ def specializesSym(tp: Type, sym: Symbol): boolean = (
+ tp.symbol == AllClass ||
+ tp.symbol == AllRefClass && (sym.owner isSubClass ObjectClass) ||
+ (tp.nonPrivateMember(sym.name).alternatives exists
+ (alt => sym == alt || specializesSym(tp.narrow, alt, sym.owner.thisType, sym)))
+ );
+
+ /** Does member `sym1' of `tp1' have a stronger type than member `sym2' of `tp2'? */
+ private def specializesSym(tp1: Type, sym1: Symbol, tp2: Type, sym2: Symbol): boolean = {
+ val info1 = tp1.memberInfo(sym1);
+ val info2 = tp2.memberInfo(sym2).substThis(tp2.symbol, tp1);
+ (sym2.isTerm &&
+ info1 <:< info2 ||
+ sym2.isAbstractType &&
+ (info2.bounds containsType info1) ||
+ sym2.isAliasType &&
+ tp2.memberType(sym2) =:= tp1.memberType(sym1))
+ }
+
+ /** A function implementing tp1 matches tp2 */
+ private def matchesType(tp1: Type, tp2: Type): boolean = Pair(tp1, tp2) match {
+ case Pair(MethodType(pts1, res1), MethodType(pts2, res2)) =>
+ (matchingParams(pts1, pts2, tp2.isInstanceOf[JavaMethodType]) && (res1 matches res2) &&
+ tp1.isInstanceOf[ImplicitMethodType] == tp2.isInstanceOf[ImplicitMethodType])
+ case Pair(PolyType(tparams1, res1), PolyType(tparams2, res2)) =>
+ (tparams1.length == tparams2.length &&
+ (res1 matches res2.substSym(tparams2, tparams1)))
+ case Pair(PolyType(List(), rtp1), _) => matchesType(rtp1, tp2)
+ case Pair(_, PolyType(List(), rtp2)) => matchesType(tp1, rtp2)
+ case Pair(MethodType(_, _), _) => false
+ case Pair(PolyType(_, _), _) => false
+ case Pair(_, MethodType(_, _)) => false
+ case Pair(_, PolyType(_, _)) => false
+ case _ =>
+ !phase.erasedTypes || tp1 =:= tp2
+ }
+
+ /** Are tps1 and tps2 lists of pairwise equivalent types? */
+ private def matchingParams(tps1: List[Type], tps2: List[Type], tps2isJava: boolean): boolean = (
+ tps1.length == tps2.length &&
+ List.forall2(tps1, tps2)((tp1, tp2) =>
+ (tp1 =:= tp2) || tps2isJava & tp1.symbol == ObjectClass && tp2.symbol == AnyClass)
+ );
+
+ /** Prepend type `tp' to closure `cl' */
+ private def addClosure(tp: Type, cl: Array[Type]): Array[Type] = {
+ val cl1 = new Array[Type](cl.length + 1);
+ assert(!tp.isInstanceOf[CompoundType], tp);//debug
+ cl1(0) = tp;
+ System.arraycopy(cl, 0, cl1, 1, cl.length);
+ cl1
+ }
+
+// Lubs and Glbs ---------------------------------------------------------
+
+ private val recLimit = 10;
+ private var recCount = 0;
+ private var giveUp: boolean = _;
+
+ /** Return op(tps), but give up if level of recursion is greater than
+ * recLimit */
+ private def limitRecursion(tps: List[Type], boundkind: String,
+ op: List[Type] => Type): Type =
+ if (recCount == recLimit) {
+ giveUp = true;
+ AnyClass.tpe
+ } else {
+ if (recCount == 0) giveUp = false;
+ val result = try {
+ recCount = recCount + 1;
+ op(tps)
+ } finally {
+ recCount = recCount - 1
+ }
+ if (recCount == 0 && giveUp) {
+ throw new TypeError("failure to compute " + boundkind +
+ " bound of types " +
+ tps.mkString("", " and ", ";\n") +
+ "an approximation is: " + result + ";\n" +
+ "additional type annotations are needed");
+ }
+ result
+ }
+
+ /** The greatest sorted upwards closed lower bound of a list of lists of
+ * types relative to the following ordering <= between lists of types:
+ *
+ * xs <= ys iff forall y in ys exists x in xs such that x <: y
+ *
+ * @See closure for a definition of sorted and upwards closed.
+ */
+ private def glbList(tss: List[List[Type]]): List[Type] = {
+ val tss1 = tss filter (ts => !ts.isEmpty);
+ if (tss1.isEmpty) List()
+ else if (tss1.tail.isEmpty) tss.head
+ else {
+ val ts0 = tss1 map (.head);
+ val sym = minSym(ts0);
+ val ts1 = elimSuper(ts0 filter (.symbol.==(sym)));
+ mergePrefixAndArgs(ts1, -1) match {
+ case Some(tp0) =>
+ tp0 :: glbList(tss1 map (ts => if (ts.head.symbol == sym) ts.tail else ts))
+ case None =>
+ throw new MalformedClosure(ts1)
+ }
+ }
+ }
+
+ /** The greatest sorted upwards closed lower bound of a list of closures.
+ * @See glbList for more explanations.
+ */
+ private def glbArray(tss: List[Array[Type]]): Array[Type] = {
+ val tss1 = tss map (ts: Array[Type] => List.fromArray(ts));
+ val glbs = glbList(tss1);
+ val result = new Array[Type](glbs.length);
+ var i = 0;
+ for (val x <- glbs.elements) { result(i) = x; i = i + 1; }
+ result;
+ // Predef.Array(glbs: _*);
+ }
+
+ /** The least sorted upwards closed upper bound of a non-empty list
+ * of lists of types.
+ * @See glbList for more explanations. */
+ private def lubList(tss: List[List[Type]]): List[Type] =
+ if (tss.tail.isEmpty) tss.head
+ else if (tss exists (.isEmpty)) List()
+ else {
+ val ts0 = tss map (.head);
+ val sym = minSym(ts0);
+ if (ts0 forall (t => t.symbol == sym))
+ mergePrefixAndArgs(elimSub(ts0), 1).toList ::: lubList(tss map (.tail))
+ else
+ lubList(tss map (ts => if (ts.head.symbol == sym) ts.tail else ts))
+ }
+
+ /** The least sorted upwards closed upper bound of a non-empty list
+ * of closures.
+ * @See lubList for more explanations. */
+ private def lubArray(tss: List[Array[Type]]): Array[Type] = {
+ var lubs = lubList(tss map (ts: Array[Type] => List.fromArray(ts)));
+ var arr = new Array[Type](lubs.length);
+ var i = 0;
+ while (i < arr.length) {
+ arr(i) = lubs.head;
+ i = i + 1;
+ lubs = lubs.tail
+ }
+ arr
+ // todo: replace by Predef.Array(lubs: _* )
+ }
+
+ /** The minimal symbol (wrt Symbol.isLess) of a list of types */
+ private def minSym(tps: List[Type]): Symbol =
+ (tps.head.symbol /: tps.tail) {
+ (sym1, tp2) => if (tp2.symbol isLess sym1) tp2.symbol else sym1
+ }
+
+ /** A minimal type list which has a given array of types as its closure */
+ def spanningTypes(ts: List[Type]): List[Type] = ts match {
+ case List() => List()
+ case first :: rest =>
+ first :: spanningTypes(
+ rest filter (t => !first.symbol.isSubClass(t.symbol)))
+ }
+
+ /** Eliminate from list of types all elements which are a supertype
+ * of some other element of the list. */
+ private def elimSuper(ts: List[Type]): List[Type] = ts match {
+ case List() => List()
+ case t :: ts1 =>
+ val rest = ts1 filter (t1 => !(t <:< t1));
+ if (rest exists (t1 => t1 <:< t)) rest else t :: rest
+ }
+
+ /** Eliminate from list of types all elements which are a subtype
+ * of some other element of the list. */
+ private def elimSub(ts: List[Type]): List[Type] = ts match {
+ case List() => List()
+ case t :: ts1 =>
+ val rest = ts1 filter (t1 => !(t1 <:< t));
+ if (rest exists (t1 => t <:< t1)) rest else t :: rest
+ }
+
+ /** The least upper bound wrt <:< of a list of types */
+ def lub(ts: List[Type]): Type = {
+ def lub0(ts0: List[Type]): Type = elimSub(ts0 map (.deconst)) match {
+ case List() => AllClass.tpe
+ case List(t) => t
+ case ts @ PolyType(tparams, _) :: _ =>
+ PolyType(
+ List.map2(tparams, List.transpose(matchingBounds(ts, tparams)))
+ ((tparam, bounds) => tparam.cloneSymbol.setInfo(glb(bounds))),
+ lub0(matchingInstTypes(ts, tparams)))
+ case ts @ MethodType(pts, _) :: rest =>
+ MethodType(pts, lub0(matchingRestypes(ts, pts)))
+ case ts @ TypeBounds(_, _) :: rest =>
+ TypeBounds(glb(ts map (.bounds.lo)), lub(ts map (.bounds.hi)))
+ case ts =>
+ val closures: List[Array[Type]] = ts map (.closure);
+ val lubBaseTypes: Array[Type] = lubArray(closures);
+ //log("closures = " + (closures map (cl => List.fromArray(cl))) + ", lubbases = " + List.fromArray(lubBaseTypes));//DEBUG
+ val lubParents = spanningTypes(List.fromArray(lubBaseTypes));
+ val lubOwner = commonOwner(ts);
+ val lubBase = intersectionType(lubParents, lubOwner);
+ if (phase.erasedTypes) lubBase
+ else {
+ val lubType = refinedType(lubParents, lubOwner);
+ val lubThisType = lubType.symbol.thisType;
+ val narrowts = ts map (.narrow);
+ def lubsym(proto: Symbol): Symbol = {
+ val prototp = lubThisType.memberInfo(proto);
+ val syms = narrowts map (t =>
+ t.nonPrivateMember(proto.name).suchThat(sym =>
+ sym.tpe matches prototp.substThis(lubThisType.symbol, t)));
+ if (syms contains NoSymbol) NoSymbol
+ else {
+ val symtypes =
+ (List.map2(narrowts, syms)
+ ((t, sym) => t.memberInfo(sym).substThis(t.symbol, lubThisType)));
+ if (settings.debug.value) log("common symbols: " + syms + ":" + symtypes);//debug
+ if (proto.isTerm)
+ proto.cloneSymbol.setInfo(lub(symtypes))
+ else if (symtypes.tail forall (symtypes.head =:=))
+ proto.cloneSymbol.setInfo(symtypes.head)
+ else {
+ def lubBounds(bnds: List[TypeBounds]): TypeBounds =
+ TypeBounds(glb(bnds map (.lo)), lub(bnds map (.hi)));
+ proto.owner.newAbstractType(proto.pos, proto.name)
+ .setInfo(lubBounds(symtypes map (.bounds)))
+ }
+ }
+ }
+ def refines(tp: Type, sym: Symbol): boolean = {
+ val syms = tp.nonPrivateMember(sym.name).alternatives;
+ !syms.isEmpty && (syms forall (alt =>
+ // todo alt != sym is strictly speaking not correct, but without it we lose
+ // efficiency.
+ alt != sym && !specializesSym(lubThisType, sym, tp, alt)))
+ }
+ for (val sym <- lubBase.nonPrivateMembers)
+ // add a refinement symbol for all non-class members of lubBase
+ // which are refined by every type in ts.
+ if (!sym.isClass && !sym.isConstructor && (narrowts forall (t => refines(t, sym))))
+ addMember(lubThisType, lubType, lubsym(sym));
+ if (lubType.decls.isEmpty) lubBase else lubType;
+ }
+ }
+
+ if (settings.debug.value) {
+ log(indent + "lub of " + ts);//debug
+ indent = indent + " ";
+ }
+ val res = limitRecursion(ts, "least upper", lub0);
+ if (settings.debug.value) {
+ indent = indent.substring(0, indent.length() - 2);
+ log(indent + "lub of " + ts + " is " + res);//debug
+ }
+ res
+ }
+
+ /** The greatest lower bound wrt <:< of a list of types */
+ def glb(ts: List[Type]): Type = {
+ def glb0(ts0: List[Type]): Type = elimSuper(ts0 map (.deconst)) match {
+ case List() => AnyClass.tpe
+ case List(t) => t
+ case ts @ PolyType(tparams, _) :: _ =>
+ PolyType(
+ List.map2(tparams, List.transpose(matchingBounds(ts, tparams)))
+ ((tparam, bounds) => tparam.cloneSymbol.setInfo(lub(bounds))),
+ glb0(matchingInstTypes(ts, tparams)))
+ case ts @ MethodType(pts, _) :: rest =>
+ MethodType(pts, glb0(matchingRestypes(ts, pts)))
+ case ts @ TypeBounds(_, _) :: rest =>
+ TypeBounds(lub(ts map (.bounds.lo)), glb(ts map (.bounds.hi)))
+ case ts =>
+ try {
+ val glbOwner = commonOwner(ts);
+ val glbBase = intersectionType(ts, glbOwner);
+ if (phase.erasedTypes) glbBase
+ else {
+ val glbType = refinedType(ts, glbOwner);
+ val glbThisType = glbType.symbol.thisType;
+ def glbsym(proto: Symbol): Symbol = {
+ val prototp = glbThisType.memberInfo(proto);
+ val syms = for (
+ val t <- ts;
+ val alt <- t.nonPrivateMember(proto.name).alternatives;
+ glbThisType.memberInfo(alt) matches prototp) yield alt;
+ val symtypes = syms map glbThisType.memberInfo;
+ assert(!symtypes.isEmpty);
+ proto.cloneSymbol.setInfo(
+ if (proto.isTerm) glb(symtypes)
+ else {
+ def isTypeBound(tp: Type) = tp match {
+ case TypeBounds(_, _) => true
+ case _ => false
+ }
+ def glbBounds(bnds: List[Type]): TypeBounds = {
+ val lo = lub(bnds map (.bounds.lo));
+ val hi = glb(bnds map (.bounds.hi));
+ if (lo <:< hi) TypeBounds(lo, hi)
+ else throw new MalformedClosure(bnds)
+ }
+ val symbounds = symtypes filter isTypeBound;
+ var result: Type =
+ if (symbounds.isEmpty)
+ TypeBounds(AllClass.tpe, AnyClass.tpe)
+ else glbBounds(symbounds);
+ for (val t <- symtypes; !isTypeBound(t))
+ if (result.bounds containsType t) result = t
+ else throw new MalformedClosure(symtypes);
+ result
+ })
+ }
+ for (val t <- ts; val sym <- t.nonPrivateMembers)
+ if (!sym.isClass && !sym.isConstructor && !(glbThisType specializes sym))
+ addMember(glbThisType, glbType, glbsym(sym));
+ if (glbType.decls.isEmpty) glbBase else glbType
+ }
+ } catch {
+ case _: MalformedClosure =>
+ if (ts forall (t => t <:< AnyRefClass.tpe)) AllRefClass.tpe
+ else AllClass.tpe
+ }
+ }
+ if (settings.debug.value) {
+ log(indent + "glb of " + ts);//debug
+ indent = indent + " ";
+ }
+ val res = limitRecursion(ts, "greatest lower", glb0);
+ if (settings.debug.value) {
+ indent = indent.substring(0, indent.length() - 2);
+ log(indent + "glb of " + ts + " is " + res);//debug
+ }
+ res
+ }
+
+ /** The most deeply nested owner that contains all the symbols
+ * of thistype or prefixless typerefs/singletype occurrences in given type */
+ private def commonOwner(t: Type): Symbol = {
+ commonOwnerMap.init;
+ commonOwnerMap.apply(t);
+ commonOwnerMap.result
+ }
+
+ /** The most deeply nested owner that contains all the symbols
+ * of thistype or prefixless typerefs/singletype occurrences in given list of types */
+ private def commonOwner(tps: List[Type]): Symbol = {
+ if (settings.debug.value) log("computing common owner of types " + tps);//debug
+ commonOwnerMap.init;
+ tps foreach { tp => commonOwnerMap.apply(tp); () }
+ commonOwnerMap.result
+ }
+
+ /** Compute lub (if variance == 1) or glb (if variance == 0) of given list of types
+ * `tps'. All types in `tps' are typerefs or singletypes with the same symbol.
+ * Return Some(x) if the computation succeeds with result `x'.
+ * Return None if the computuation fails.
+ */
+ private def mergePrefixAndArgs(tps: List[Type], variance: int): Option[Type] = tps match {
+ case List(tp) =>
+ Some(tp)
+ case TypeRef(_, sym, _) :: rest =>
+ val pres = tps map (.prefix);
+ val pre = if (variance == 1) lub(pres) else glb(pres);
+ val argss = tps map (.typeArgs);
+ val args =
+ (List.map2(sym.typeParams, List.transpose(argss))
+ ((tparam, as) =>
+ if (tparam.variance == variance) lub(as)
+ else if (tparam.variance == -variance) glb(as)
+ else NoType));
+ try {
+ if (args contains NoType) None
+ else Some(typeRef(pre, sym, args))
+ } catch {
+ case ex: MalformedType => None
+ }
+ case SingleType(_, sym) :: rest =>
+ val pres = tps map (.prefix);
+ val pre = if (variance == 1) lub(pres) else glb(pres);
+ try {
+ Some(singleType(pre, sym))
+ } catch {
+ case ex: MalformedType => None
+ }
+ }
+
+ /** Make symbol `sym' a member of scope `tp.decls' where `thistp' is the narrowed
+ * owner type of the scope */
+ private def addMember(thistp: Type, tp: Type, sym: Symbol): unit = {
+ if (settings.debug.value) log("add member " + sym);//debug
+ if (!(thistp specializes sym)) {
+ if (sym.isTerm)
+ for (val alt <- tp.nonPrivateDecl(sym.name).alternatives)
+ if (specializesSym(thistp, sym, thistp, alt))
+ tp.decls unlink alt;
+ tp.decls enter sym
+ }
+ }
+
+ /** All types in list must be polytypes with type parameter lists of
+ * same length as tparams.
+ * Returns list of list of bounds infos, where corresponding type
+ * parameters are renamed to tparams.
+ */
+ private def matchingBounds(tps: List[Type], tparams: List[Symbol]): List[List[Type]] =
+ tps map {
+ case PolyType(tparams1, _) if (tparams1.length == tparams.length) =>
+ tparams1 map (tparam => tparam.info.substSym(tparams1, tparams))
+ case _ =>
+ throw new Error("lub/glb of incompatible types: " + tps.mkString("", " and ", ""))
+ }
+
+ /** All types in list must be polytypes with type parameter lists of
+ * same length as tparams.
+ * Returns list of instance types, where corresponding type
+ * parameters are renamed to tparams.
+ */
+ private def matchingInstTypes(tps: List[Type], tparams: List[Symbol]): List[Type] =
+ tps map {
+ case PolyType(tparams1, restpe) if (tparams1.length == tparams.length) =>
+ restpe.substSym(tparams1, tparams)
+ case _ =>
+ throw new Error("lub/glb of incompatible types: " + tps.mkString("", " and ", ""))
+ }
+
+ /** All types in list must be method types with equal parameter types.
+ * Returns list of their result types.
+ */
+ private def matchingRestypes(tps: List[Type], pts: List[Type]): List[Type] =
+ tps map {
+ case MethodType(pts1, res) if (isSameTypes(pts1, pts)) =>
+ res
+ case _ =>
+ throw new Error("lub/glb of incompatible types: " + tps.mkString("", " and ", ""))
+ }
+
+// Errors and Diagnostics ---------------------------------------------------------
+
+ /** An exception signalling a type error */
+ class TypeError(val msg: String) extends java.lang.Error(msg);
+
+ /** An exception signalling a malformed type */
+ class MalformedType(msg: String) extends TypeError(msg) {
+ def this(pre: Type, tp: String) = this("malformed type: " + pre + "#" + tp);
+ }
+
+ /** An exception signalling a malformed closure */
+ class MalformedClosure(ts: List[Type])
+ extends TypeError("no common type instance of base types " +
+ ts.mkString("", " and ", "") + " exists");
+
+ /** An exception signalling a variance annotation/usage conflict */
+ class VarianceError(msg: String) extends TypeError(msg);
+
+ /** The current indentation string for traces */
+ private var indent: String = "";
+
+ /** Perform operation `p' on arguments `tp1', `arg2' and print trace of computation */
+ private def explain[T](op: String, p: (Type, T) => boolean, tp1: Type, arg2: T): boolean = {
+ System.out.println(indent + tp1 + " " + op + " " + arg2 + "?");
+ indent = indent + " ";
+ val result = p(tp1, arg2);
+ indent = indent.substring(0, indent.length() - 2);
+ System.out.println(indent + result);
+ result
+ }
+
+ /** If option `explaintypes' is set, print a subtype trace for `found' <: `required' */
+ def explainTypes(found: Type, required: Type): unit =
+ if (settings.explaintypes.value) {
+ val s = explainSwitch;
+ explainSwitch = true;
+ found <:< required;
+ explainSwitch = s
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileConstants.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileConstants.scala
new file mode 100644
index 0000000000..f023552443
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileConstants.scala
@@ -0,0 +1,42 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.symtab.classfile;
+
+object ClassfileConstants {
+
+ final val JAVA_MAGIC = 0xCAFEBABE;
+ final val JAVA_MAJOR_VERSION = 45;
+ final val JAVA_MINOR_VERSION = 3;
+
+ final val JAVA_ACC_PUBLIC = 0x0001;
+ final val JAVA_ACC_PRIVATE = 0x0002;
+ final val JAVA_ACC_PROTECTED = 0x0004;
+ final val JAVA_ACC_STATIC = 0x0008;
+ final val JAVA_ACC_FINAL = 0x0010;
+ final val JAVA_ACC_SUPER = 0x0020;
+ final val JAVA_ACC_SYNCHRONIZED = 0x0020;
+ final val JAVA_ACC_VOLATILE = 0x0040;
+ final val JAVA_ACC_BRIDGE = 0x0040;
+ final val JAVA_ACC_TRANSIENT = 0x0080;
+ final val JAVA_ACC_NATIVE = 0x0100;
+ final val JAVA_ACC_INTERFACE = 0x0200;
+ final val JAVA_ACC_ABSTRACT = 0x0400;
+ final val JAVA_ACC_STRICT = 0x0800;
+ final val JAVA_ACC_SYNTHETIC = 0x1000;
+
+ final val CONSTANT_UTF8 = 1;
+ final val CONSTANT_UNICODE = 2;
+ final val CONSTANT_INTEGER = 3;
+ final val CONSTANT_FLOAT = 4;
+ final val CONSTANT_LONG = 5;
+ final val CONSTANT_DOUBLE = 6;
+ final val CONSTANT_CLASS = 7;
+ final val CONSTANT_STRING = 8;
+ final val CONSTANT_FIELDREF = 9;
+ final val CONSTANT_METHODREF = 10;
+ final val CONSTANT_INTFMETHODREF = 11;
+ final val CONSTANT_NAMEANDTYPE = 12;
+}
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
new file mode 100644
index 0000000000..0e56cf8824
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -0,0 +1,402 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+/* Ideas to extend this to an icode reader:
+
+ 1. Parse classfile a second time, creating a hashmap `code' that associates method symbols with code.
+ 2. For every method symbol `meth' in the new scope:
+
+ new = oldclass.info.decl(meth.name).suchThat(old => old.tpe =:= meth.tpe)
+
+ code(new) = code(meth)
+*/
+package scala.tools.nsc.symtab.classfile;
+
+import scala.tools.nsc.util.Position;
+import scala.tools.util.AbstractFile;
+import scala.tools.util.AbstractFileReader;
+
+import java.io.IOException;
+
+abstract class ClassfileParser {
+
+ val global: Global;
+ import global._;
+
+ import ClassfileConstants._;
+ import Flags._;
+
+ private var in: AbstractFileReader = _; // the class file
+ private var clazz: Symbol = _; // the class symbol containing dynamic members
+ private var staticModule: Symbol = _; // the module symbol containing static members
+ private var instanceDefs: Scope = _; // the scope of all instance definitions
+ private var staticDefs: Scope = _; // the scope of all static definitions
+ private var pool: ConstantPool = _; // the classfile's constant pool
+ private var isScala: boolean = _; // does class file describe a scala class?
+ private var hasMeta: boolean = _; // does class file contain jaco meta attribute?s
+ private var busy: boolean = false; // lock to detect recursive reads
+
+ private object metaParser extends MetaParser {
+ val global: ClassfileParser.this.global.type = ClassfileParser.this.global
+ }
+
+ private object unpickler extends UnPickler {
+ val global: ClassfileParser.this.global.type = ClassfileParser.this.global
+ }
+
+ def parse(file: AbstractFile, root: Symbol): unit = {
+ assert(!busy);
+ busy = true;
+ this.in = new AbstractFileReader(file);
+ if (root.isModule) {
+ this.clazz = root.linkedClass;
+ this.staticModule = root
+ } else {
+ this.clazz = root;
+ this.staticModule = root.linkedModule
+ }
+ this.isScala = false;
+ this.hasMeta = false;
+ try {
+ parseHeader;
+ this.pool = new ConstantPool;
+ parseClass()
+ } catch {
+ case e: RuntimeException =>
+ if (settings.debug.value) e.printStackTrace();
+ throw new IOException("class file '" + in.file + "' is broken")
+ }
+ busy = false
+ }
+
+ private def statics: Symbol = staticModule.moduleClass;
+
+ private def parseHeader: unit = {
+ val magic = in.nextInt();
+ if (magic != JAVA_MAGIC)
+ throw new IOException("class file '" + in.file + "' "
+ + "has wrong magic number 0x" + Integer.toHexString(magic)
+ + ", should be 0x" + Integer.toHexString(JAVA_MAGIC));
+ val minorVersion = in.nextChar();
+ val majorVersion = in.nextChar();
+ if ((majorVersion < JAVA_MAJOR_VERSION) ||
+ ((majorVersion == JAVA_MAJOR_VERSION) &&
+ (minorVersion < JAVA_MINOR_VERSION)))
+ throw new IOException("class file '" + in.file + "' "
+ + "has unknown version "
+ + majorVersion + "." + minorVersion
+ + ", should be at least "
+ + JAVA_MAJOR_VERSION + "." + JAVA_MINOR_VERSION);
+
+ }
+
+ class ConstantPool {
+ private val len = in.nextChar();
+ private val starts = new Array[int](len);
+ private val values = new Array[Object](len);
+ private val internalized = new Array[Name](len);
+ { var i = 1;
+ while (i < starts.length) {
+ starts(i) = in.bp;
+ i = i + 1;
+ in.nextByte() match {
+ case CONSTANT_UTF8 | CONSTANT_UNICODE =>
+ in.skip(in.nextChar());
+ case CONSTANT_CLASS | CONSTANT_STRING =>
+ in.skip(2);
+ case CONSTANT_FIELDREF | CONSTANT_METHODREF | CONSTANT_INTFMETHODREF | CONSTANT_NAMEANDTYPE | CONSTANT_INTEGER | CONSTANT_FLOAT =>
+ in.skip(4);
+ case CONSTANT_LONG | CONSTANT_DOUBLE =>
+ in.skip(8);
+ i = i + 1
+ case _ =>
+ errorBadTag(in.bp - 1);
+ }
+ }
+ }
+
+ def getName(index: int): Name = {
+ if (index <= 0 || len <= index) errorBadIndex(index);
+ var name = values(index).asInstanceOf[Name];
+ if (name == null) {
+ val start = starts(index);
+ if (in.buf(start) != CONSTANT_UTF8) errorBadTag(start);
+ name = newTermName(in.buf, start + 3, in.getChar(start + 1));
+ values(index) = name;
+ }
+ name
+ }
+
+ def getExternalName(index: int): Name = {
+ if (index <= 0 || len <= index) errorBadIndex(index);
+ if (internalized(index) == null) {
+ internalized(index) = getName(index).replace('/', '.')
+ }
+ internalized(index)
+ }
+
+ def getClassSymbol(index: int): Symbol = {
+ if (index <= 0 || len <= index) errorBadIndex(index);
+ var c = values(index).asInstanceOf[Symbol];
+ if (c == null) {
+ val start = starts(index);
+ if (in.buf(start) != CONSTANT_CLASS) errorBadTag(start);
+ val name = getExternalName(in.getChar(start + 1));
+ c = definitions.getClass(name);
+ values(index) = c;
+ }
+ c
+ }
+
+ def getType(index: int): Type =
+ sigToType(getExternalName(index));
+
+ def getSuperClass(index: int): Symbol =
+ if (index == 0) definitions.AnyClass else getClassSymbol(index);
+
+ def getConstant(index: int): Constant = {
+ if (index <= 0 || len <= index) errorBadIndex(index);
+ var value = values(index);
+ if (value == null) {
+ val start = starts(index);
+ value = in.buf(start) match {
+ case CONSTANT_STRING =>
+ Constant(getName(in.getChar(start + 1)).toString())
+ case CONSTANT_INTEGER =>
+ Constant(in.getInt(start + 1))
+ case CONSTANT_FLOAT =>
+ Constant(in.getFloat(start + 1))
+ case CONSTANT_LONG =>
+ Constant(in.getLong(start + 1))
+ case CONSTANT_DOUBLE =>
+ Constant(in.getDouble(start + 1))
+ case _ =>
+ errorBadTag(start);
+ }
+ values(index) = value;
+ }
+ value.asInstanceOf[Constant]
+ }
+
+ /** Throws an exception signaling a bad constant index. */
+ private def errorBadIndex(index: int) =
+ throw new RuntimeException("bad constant pool index: " + index);
+
+ /** Throws an exception signaling a bad tag at given address. */
+ private def errorBadTag(start: int) =
+ throw new RuntimeException("bad constant pool tag " + in.buf(start) + " at byte " + start);
+ }
+
+ private def sigToType(name: Name): Type = {
+ var index = 0;
+ val end = name.length;
+ def objToAny(tp: Type): Type =
+ if (tp.symbol == definitions.ObjectClass) definitions.AnyClass.tpe
+ else tp;
+ def paramsigs2types: List[Type] =
+ if (name(index) == ')') { index = index + 1; List() }
+ else objToAny(sig2type) :: paramsigs2types;
+ def sig2type: Type = {
+ val tag = name(index); index = index + 1;
+ tag match {
+ case 'B' => definitions.ByteClass.tpe
+ case 'C' => definitions.CharClass.tpe
+ case 'D' => definitions.DoubleClass.tpe
+ case 'F' => definitions.FloatClass.tpe
+ case 'I' => definitions.IntClass.tpe
+ case 'J' => definitions.LongClass.tpe
+ case 'S' => definitions.ShortClass.tpe
+ case 'V' => definitions.UnitClass.tpe
+ case 'Z' => definitions.BooleanClass.tpe
+ case 'L' =>
+ val start = index;
+ while (name(index) != ';') { index = index + 1 }
+ val end = index;
+ index = index + 1;
+ definitions.getClass(name.subName(start, end)).tpe
+ case '[' =>
+ while ('0' <= name(index) && name(index) <= '9') index = index + 1;
+ appliedType(definitions.ArrayClass.tpe, List(sig2type))
+ case '(' =>
+ JavaMethodType(paramsigs2types, sig2type)
+ }
+ }
+ sig2type
+ }
+
+ def parseClass(): unit = {
+ val jflags = in.nextChar();
+ var sflags = transFlags(jflags);
+ if ((sflags & DEFERRED) != 0) sflags = sflags & ~DEFERRED | ABSTRACT;
+ val c = pool.getClassSymbol(in.nextChar());
+ if (c != clazz)
+ throw new IOException("class file '" + in.file + "' contains wrong " + clazz);
+ val superType = pool.getSuperClass(in.nextChar()).tpe;
+ val ifaceCount = in.nextChar();
+ val parents = (superType ::
+ (for (val i <- List.range(0, ifaceCount))
+ yield pool.getSuperClass(in.nextChar()).tpe));
+ instanceDefs = new Scope();
+ staticDefs = new Scope();
+ val classInfo = ClassInfoType(parents, instanceDefs, clazz);
+ val staticInfo = ClassInfoType(List(), staticDefs, statics);
+
+ val curbp = in.bp;
+ skipMembers(); // fields
+ skipMembers(); // methods
+ parseAttributes(clazz, classInfo);
+ if (!isScala) {
+ clazz.setFlag(sflags);
+ if (!hasMeta) {
+ clazz.setInfo(classInfo);
+ }
+ statics.setInfo(staticInfo);
+ staticModule.setInfo(statics.tpe);
+ staticModule.setFlag(JAVA);
+ staticModule.moduleClass.setFlag(JAVA);
+ in.bp = curbp;
+ val fieldCount = in.nextChar();
+ for (val i <- Iterator.range(0, fieldCount)) parseField();
+ val methodCount = in.nextChar();
+ for (val i <- Iterator.range(0, methodCount)) parseMethod();
+ if (instanceDefs.lookup(nme.CONSTRUCTOR) == NoSymbol && (sflags & INTERFACE) == 0) {
+ //System.out.println("adding constructor to " + clazz);//DEBUG
+ instanceDefs.enter(
+ clazz.newConstructor(Position.NOPOS)
+ .setFlag(clazz.flags & ConstrFlags).setInfo(MethodType(List(), clazz.tpe)));
+ }
+ }
+ }
+
+ def parseField(): unit = {
+ val jflags = in.nextChar();
+ var sflags = transFlags(jflags);
+ if ((sflags & FINAL) == 0) sflags = sflags | MUTABLE;
+ if ((sflags & PRIVATE) != 0) {
+ in.skip(4); skipAttributes();
+ } else {
+ val name = pool.getName(in.nextChar());
+ val info = pool.getType(in.nextChar());
+ val sym = getOwner(jflags)
+ .newValue(Position.NOPOS, name).setFlag(sflags).setInfo(info);
+ parseAttributes(sym, info);
+ getScope(jflags).enter(sym);
+ }
+ }
+
+ def parseMethod(): unit = {
+ val jflags = in.nextChar();
+ var sflags = transFlags(jflags);
+ if ((sflags & JAVA_ACC_BRIDGE) != 0) sflags = sflags | PRIVATE;
+ if ((sflags & PRIVATE) != 0) {
+ in.skip(4); skipAttributes();
+ } else {
+ val name = pool.getName(in.nextChar());
+ var info = pool.getType(in.nextChar());
+ if (name == nme.CONSTRUCTOR)
+ info match {
+ case MethodType(formals, restpe) =>
+ assert(restpe.symbol == definitions.UnitClass);
+ info = MethodType(formals, clazz.tpe)
+ }
+ val sym = getOwner(jflags)
+ .newMethod(Position.NOPOS, name).setFlag(sflags).setInfo(info);
+ parseAttributes(sym, info);
+ getScope(jflags).enter(sym);
+ }
+ }
+
+ def parseAttributes(sym: Symbol, symtype: Type): unit = {
+ def parseAttribute(): unit = {
+ val attrName = pool.getName(in.nextChar());
+ val attrLen = in.nextInt();
+ attrName match {
+ case nme.SyntheticATTR =>
+ sym.setFlag(SYNTHETIC);
+ in.skip(attrLen)
+ case nme.BridgeATTR =>
+ sym.setFlag(BRIDGE);
+ in.skip(attrLen)
+ case nme.DeprecatedATTR =>
+ sym.setFlag(DEPRECATED);
+ in.skip(attrLen)
+ case nme.ConstantValueATTR =>
+ val c = pool.getConstant(in.nextChar());
+ val c1 = c convertTo symtype;
+ sym.setInfo(ConstantType(c1));
+ case nme.InnerClassesATTR =>
+ parseInnerClasses()
+ case nme.ScalaSignatureATTR =>
+ unpickler.unpickle(in.buf, in.bp, clazz, staticModule);
+ this.isScala = true;
+ case nme.JacoMetaATTR =>
+ val meta = pool.getName(in.nextChar()).toString().trim();
+ metaParser.parse(meta, sym, symtype);
+ this.hasMeta = true;
+ case _ =>
+ in.skip(attrLen)
+ }
+ }
+ def parseInnerClasses(): unit = {
+ for (val i <- Iterator.range(0, in.nextChar())) {
+ val innerIndex = in.nextChar();
+ val outerIndex = in.nextChar();
+ val nameIndex = in.nextChar();
+ val jflags = in.nextChar();
+ if (innerIndex != 0 && outerIndex != 0 && nameIndex != 0 &&
+ (jflags & (JAVA_ACC_PUBLIC | JAVA_ACC_PROTECTED)) != 0 &&
+ pool.getClassSymbol(outerIndex) == sym) {
+ val innerAlias = getOwner(jflags)
+ .newAliasType(Position.NOPOS, pool.getName(nameIndex).toTypeName)
+ .setInfo(pool.getClassSymbol(innerIndex).tpe);
+ getScope(jflags).enter(innerAlias);
+ }
+ }
+ }
+ val attrCount = in.nextChar();
+ for (val i <- Iterator.range(0, attrCount)) parseAttribute()
+ }
+
+ def skipAttributes(): unit = {
+ val attrCount = in.nextChar();
+ for (val i <- Iterator.range(0, attrCount)) {
+ in.skip(2); in.skip(in.nextInt())
+ }
+ }
+
+ def skipMembers(): unit = {
+ val memberCount = in.nextChar();
+ for (val i <- Iterator.range(0, memberCount)) {
+ in.skip(6); skipAttributes()
+ }
+ }
+
+ private def getOwner(flags: int): Symbol =
+ if ((flags & JAVA_ACC_STATIC) != 0) statics else clazz;
+
+ private def getScope(flags: int): Scope =
+ if ((flags & JAVA_ACC_STATIC) != 0) staticDefs else instanceDefs;
+
+ private def transFlags(flags: int): long = {
+ var res = 0l;
+ if ((flags & JAVA_ACC_PRIVATE) != 0)
+ res = res | PRIVATE
+ else if ((flags & JAVA_ACC_PROTECTED) != 0)
+ res = res | PROTECTED
+ else if ((flags & JAVA_ACC_PUBLIC) == 0)
+ res = res | PRIVATE;
+ if ((flags & JAVA_ACC_ABSTRACT) != 0)
+ res = res | DEFERRED;
+ if ((flags & JAVA_ACC_FINAL) != 0)
+ res = res | FINAL;
+ if ((flags & JAVA_ACC_INTERFACE) != 0)
+ res = res | TRAIT | INTERFACE | ABSTRACT;
+ if ((flags & JAVA_ACC_SYNTHETIC) != 0)
+ res = res | SYNTHETIC;
+ if ((flags & JAVA_ACC_STATIC) != 0)
+ res = res | STATIC;
+ res | JAVA;
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala
new file mode 100644
index 0000000000..eca5da7091
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala
@@ -0,0 +1,153 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.symtab.classfile;
+
+import java.util.{StringTokenizer, NoSuchElementException}
+import util.ListBuffer;
+import scala.tools.nsc.util.Position;
+
+abstract class MetaParser{
+
+ val global: Global;
+ import global._;
+
+ private var scanner: StringTokenizer = _;
+ private var owner: Symbol = _;
+ private var ownertype: Type = _;
+ private var token: String = _;
+ private var locals: Scope = null;
+
+ def parse(meta: String, sym: Symbol, symtype: Type): unit = {
+ //System.out.println("parse meta for " + sym + ":" + meta + ", locals = " + locals);//DEBUG
+ this.scanner = new StringTokenizer(meta, "()[], \t<;", true);
+ this.owner = sym;
+ this.ownertype = symtype;
+ nextToken();
+ if (token == "class") parseClass()
+ else if (token == "method") parseMethod()
+ else if (token == "field") parseField()
+ else if (token == "constr") parseConstr()
+ else owner.setInfo(symtype);
+ }
+
+ protected def nextToken(): unit =
+ try {
+ do { token = scanner.nextToken().trim() } while (token.length() == 0)
+ } catch {
+ case ex: NoSuchElementException => token = ""
+ }
+
+ protected def parseType(): Type = {
+ val str = token;
+ nextToken();
+ val sym = locals.lookup(newTypeName(str));
+ if (sym != NoSymbol) sym.tpe
+ else {
+ val tp = definitions.getClass(str).tpe;
+ if (token != "[") tp
+ else {
+ val args = new ListBuffer[Type];
+ do {
+ nextToken(); args += parseType();
+ } while (token == ",");
+ nextToken();
+ appliedType(tp, args.toList)
+ }
+ }
+ }
+
+ protected def parseTypeParam(): Symbol = {
+ val vflag =
+ if (token == "+") { nextToken(); Flags.COVARIANT }
+ else if (token == "-") { nextToken(); Flags.CONTRAVARIANT }
+ else 0;
+ assert(token.startsWith("?"));
+ val sym = owner.newTypeParameter(Position.NOPOS, newTypeName(token)).setFlag(vflag);
+ nextToken();
+ val lo = if (token == ">") { nextToken(); parseType() } else definitions.AllClass.tpe;
+ val hi = if (token == "<") { nextToken(); parseType() } else definitions.AnyClass.tpe;
+ sym.setInfo(TypeBounds(lo, hi));
+ locals enter sym;
+ sym
+ }
+
+ protected def parseTypeParams(): List[Symbol] = {
+ nextToken();
+ val syms = new ListBuffer[Symbol];
+ if (token != "]") {
+ syms += parseTypeParam();
+ while (token == ",") {
+ nextToken(); syms += parseTypeParam();
+ }
+ }
+ assert(token == "]");
+ syms.toList
+ }
+
+ protected def parseParams(): List[Type] = {
+ nextToken();
+ val tps = new ListBuffer[Type];
+ if (token != ")") {
+ tps += parseType();
+ while (token == ",") {
+ nextToken(); tps += parseType();
+ }
+ }
+ assert(token == ")");
+ tps.toList
+ }
+
+ protected def parseClass(): unit = {
+ locals = new Scope();
+ def parse(): Type = {
+ nextToken();
+ if (token == "[") {
+ PolyType(parseTypeParams(), parse())
+ } else if (token == "extends") {
+ val tps = new ListBuffer[Type];
+ do {
+ nextToken(); tps += parseType()
+ } while (token == "with");
+ ownertype match {
+ case ClassInfoType(parents, decls, clazz) =>
+ ClassInfoType(tps.toList, decls, clazz)
+ }
+ } else ownertype
+ }
+ owner.setInfo(parse());
+ assert(token == ";")
+ }
+
+ protected def parseMethod(): unit = {
+ val globals = locals;
+ locals = if (locals == null) new Scope() else new Scope(locals);
+ def parse(): Type = {
+ nextToken();
+ if (token == "[") PolyType(parseTypeParams(), parse())
+ else if (token == "(") MethodType(parseParams(), parse())
+ else parseType()
+ }
+ owner.setInfo(parse());
+ locals = globals;
+ assert(token == ";")
+ }
+
+ protected def parseField(): unit = {
+ nextToken();
+ owner.setInfo(parseType());
+ assert(token == ";")
+ }
+
+ protected def parseConstr(): unit = {
+ def parse(): Type = {
+ nextToken();
+ if (token == "(") MethodType(parseParams(), parse())
+ else owner.owner.tpe
+ }
+ owner.setInfo(parse());
+ assert(token == ";")
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/PickleBuffer.scala b/src/compiler/scala/tools/nsc/symtab/classfile/PickleBuffer.scala
new file mode 100644
index 0000000000..aed16bf057
--- /dev/null
+++ b/src/compiler/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/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala b/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala
new file mode 100644
index 0000000000..220b4bc6b5
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala
@@ -0,0 +1,99 @@
+/* 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 [alias_Ref]
+ * | 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}
+ * | 22 IMPLICITMETHODtpe len_Nat tpe_Ref {tpe_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
+ * | 36 ATTRIBUTE sym_Ref type_Ref {constant_Ref} <not yet>
+ * 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 MajorVersion = 2;
+ val MinorVersion = 0;
+
+ final val TERMname = 1;
+ final val TYPEname = 2;
+ final val NONEsym = 3;
+ final val TYPEsym = 4;
+ final val ALIASsym = 5;
+ final val CLASSsym = 6;
+ final val MODULEsym = 7;
+ final val VALsym = 8;
+ final val EXTref = 9;
+ final val EXTMODCLASSref = 10;
+ final val NOtpe = 11;
+ final val NOPREFIXtpe = 12;
+ final val THIStpe = 13;
+ final val SINGLEtpe = 14;
+ final val CONSTANTtpe = 15;
+ final val TYPEREFtpe = 16;
+ final val TYPEBOUNDStpe = 17;
+ final val REFINEDtpe = 18;
+ final val CLASSINFOtpe = 19;
+ final val METHODtpe = 20;
+ final val POLYtpe = 21;
+ final val IMPLICITMETHODtpe = 22;
+ final val LITERAL = 23; // base line for literals
+ final val LITERALunit = 24;
+ final val LITERALboolean = 25;
+ final val LITERALbyte = 26;
+ final val LITERALshort = 27;
+ final val LITERALchar = 28;
+ final val LITERALint = 29;
+ final val LITERALlong = 30;
+ final val LITERALfloat = 31;
+ final val LITERALdouble = 32;
+ final val LITERALstring = 33;
+ final val LITERALnull = 34;
+ final val LITERALzero = 35;
+ final val ATTRIBUTE = 40;
+
+ final val firstSymTag = NONEsym;
+ final val lastSymTag = VALsym;
+ final val firstTypeTag = NOtpe;
+ final val lastTypeTag = POLYtpe;
+}
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
new file mode 100644
index 0000000000..5ecd30fcd1
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
@@ -0,0 +1,244 @@
+/* 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 extends SubComponent {
+ import global._;
+
+ val phaseName = "pickler";
+ def newPhase(prev: Phase): StdPhase = new PicklePhase(prev);
+
+ class PicklePhase(prev: Phase) extends StdPhase(prev) {
+ def apply(unit: CompilationUnit): unit = {
+ def pickle(tree: Tree): unit = {
+
+ def add(sym: Symbol, pickle: Pickle) = {
+ if (!sym.isExternal && !currentRun.symData.contains(sym)) {
+ if (settings.debug.value) log("pickling " + sym);
+ pickle.putSymbol(sym);
+ currentRun.symData(sym) = pickle;
+ }
+ }
+
+ tree match {
+ case PackageDef(_, stats) => stats foreach pickle;
+ case ClassDef(_, _, _, _, _) | ModuleDef(_, _, _) =>
+ val sym = tree.symbol;
+ val pickle = new Pickle(sym.name.toTermName, sym.owner);
+ add(sym, pickle);
+ add(sym.linkedSym, pickle);
+ pickle.finish
+ case _ =>
+ }
+ }
+ pickle(unit.body);
+ }
+ }
+
+ 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[AnyRef, int];
+
+ /** Is root in symbol.owner*? */
+ private def isLocal(sym: Symbol): boolean = (
+ sym.isRefinementClass ||
+ 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)) {
+ if (isLocal(sym)) {
+ putEntry(sym.name);
+ putSymbol(sym.owner);
+ putType(sym.info);
+ if (sym.thisSym != sym)
+ putType(sym.typeOfThis);
+ putSymbol(sym.alias);
+ //for (val attr <- sym.attributes) putAttribute(sym, attr);
+ } 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(value) =>
+ 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(c: Constant) =
+ if (putEntry(c) && c.tag == StringTag) putEntry(newTermName(c.stringValue));
+
+/*
+ private def putAttribute(attr: AttrInfo): unit = if (putEntry(attr)) {
+ putType(attr._1);
+ for (val c <- attr._2) putConstant(c);
+ }
+*/
+ // 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: AnyRef): unit = writeNat(index(ref));
+ private def writeRefs(refs: List[AnyRef]): 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);
+ 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: 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 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.symbol); writeRefs(parents); REFINEDtpe
+ case ClassInfoType(parents, decls, clazz) =>
+ writeRef(clazz); writeRefs(parents); CLASSINFOtpe
+ case MethodType(formals, restpe) =>
+ writeRef(restpe); writeRefs(formals);
+ if (entry.isInstanceOf[ImplicitMethodType]) IMPLICITMETHODtpe
+ else METHODtpe
+ case PolyType(tparams, restpe) =>
+ writeRef(restpe); writeRefs(tparams); POLYtpe
+ 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(Float.floatToIntBits(c.floatValue))
+ else if (c.tag == DoubleTag) writeLong(Double.doubleToLongBits(c.doubleValue));
+ else if (c.tag == StringTag) writeRef(newTermName(c.stringValue));
+ LITERAL + c.tag
+/*
+ case Pair(tp, cs) =>
+ writeRef(tp);
+ for (val c <- cs) writeRef(cs);
+ ATTRIBUTE
+*/
+ 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(MajorVersion);
+ writeNat(MinorVersion);
+ writeNat(ep);
+ if (settings.debug.value) log("" + ep + " entries");//debug
+ for (val i <- Iterator.range(0, ep)) writeEntry(entries(i))
+ }
+ }
+}
+
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/SymblfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/SymblfileParser.scala
new file mode 100644
index 0000000000..cb7e401b1c
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/SymblfileParser.scala
@@ -0,0 +1,31 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.symtab.classfile;
+
+import scala.tools.util.{AbstractFile, AbstractFileReader};
+
+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/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
new file mode 100644
index 0000000000..70c50e592b
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
@@ -0,0 +1,260 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.symtab.classfile;
+
+import scala.tools.nsc.util.Position;
+import scala.tools.util.UTF8Codec;
+import java.lang.{Float, Double};
+import Flags._;
+import PickleFormat._;
+import collection.mutable.HashMap;
+
+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 =>
+ ex.printStackTrace();//debug
+
+ throw new RuntimeException("error reading Scala signature of " + classRoot.nameString + ": " + 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);
+
+ checkVersion();
+ private val index = createIndex;
+ private val entries = new Array[AnyRef](index.length);
+ private val symScopes = new HashMap[Symbol, Scope];
+
+ 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
+
+ private def checkVersion() = {
+ val major = readNat();
+ val minor = readNat();
+ if (major != MajorVersion || minor > MinorVersion)
+ throw new TypeError("Scala signature " + classRoot.name +
+ " has wrong version\n expected: " +
+ MajorVersion + "." + MinorVersion +
+ "\n found: " + major + "." + minor)
+ }
+
+ /** The scope associated with given symbol */
+ private def symScope(sym: Symbol) = symScopes.get(sym) match {
+ case None => val s = new Scope(); symScopes(sym) = s; s
+ case Some(s) => s
+ }
+
+ /** Does entry represent an (internal) symbol */
+ private def isSymbolEntry(i: int): boolean = {
+ val tag = bytes(index(i));
+ (firstSymTag <= tag && tag <= lastSymTag &&
+ (tag != CLASSsym || !isRefinementSymbolEntry(i)))
+ }
+
+ /** Does entry represent a refinement symbol?
+ * pre: Entry is a class symbol
+ */
+ private def isRefinementSymbolEntry(i: int): boolean = {
+ val savedIndex = readIndex;
+ readIndex = index(i);
+ if (readByte() != CLASSsym) assert(false);
+ readNat();
+ val result = readNameRef() == nme.REFINE_CLASS_NAME.toTypeName;
+ readIndex = savedIndex;
+ result
+ }
+
+ /** If entry at `i' is undefined, define it by performing operation `op' with
+ * readIndex at start of i'th entry. Restore readIndex afterwards. */
+ 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();
+ 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 (name == classRoot.name && owner == classRoot.owner)
+ if ((flags & MODULE) != 0) moduleRoot.moduleClass
+ else classRoot
+ else
+ if ((flags & MODULE) != 0) owner.newModuleClass(Position.NOPOS, name)
+ else owner.newClass(Position.NOPOS, name);
+ if (readIndex != end) sym.typeOfThis = new LazyTypeRef(readNat())
+ case MODULEsym =>
+ val clazz = at(inforef, readType).symbol;
+ sym =
+ if (name == moduleRoot.name && owner == moduleRoot.owner) moduleRoot
+ else {
+ assert(clazz.isInstanceOf[ModuleClassSymbol], clazz);
+ val mclazz = clazz.asInstanceOf[ModuleClassSymbol];
+ val m = owner.newModule(Position.NOPOS, name, mclazz);
+ mclazz.setSourceModule(m);
+ m
+ }
+ case VALsym =>
+ sym = if (name == moduleRoot.name && owner == moduleRoot.owner) moduleRoot.resetFlag(MODULE)
+ else owner.newValue(Position.NOPOS, name)
+ case _ =>
+ errorBadSignature("bad symbol tag: " + tag);
+ }
+ sym.setFlag(flags);
+ if (readIndex != end) assert(sym hasFlag (SUPERACCESSOR | PARAMACCESSOR));
+ if (sym hasFlag SUPERACCESSOR) assert(readIndex != end);
+ sym.setInfo(
+ if (readIndex != end) new LazyTypeRefAndAlias(inforef, readNat())
+ else new LazyTypeRef(inforef));
+ if (sym.owner.isClass && sym != classRoot && sym != moduleRoot &&
+ !sym.isModuleClass && !sym.isRefinementClass && !sym.isTypeParameter)
+ symScope(sym.owner) 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(readConstantRef())
+ case TYPEREFtpe =>
+ rawTypeRef(readTypeRef(), readSymbolRef(), until(end, readTypeRef))
+ case TYPEBOUNDStpe =>
+ TypeBounds(readTypeRef(), readTypeRef())
+ case REFINEDtpe =>
+ val clazz = readSymbolRef();
+/*
+ val ps = until(end, readTypeRef);
+ val dcls = symScope(clazz);
+ new RefinedType(ps, dcls) { override def symbol = clazz }
+*/
+ new RefinedType(until(end, readTypeRef), symScope(clazz)) { override def symbol = clazz }
+ case CLASSINFOtpe =>
+ val clazz = readSymbolRef();
+ ClassInfoType(until(end, readTypeRef), symScope(clazz), clazz)
+ case METHODtpe =>
+ val restpe = readTypeRef();
+ MethodType(until(end, readTypeRef), restpe)
+ case IMPLICITMETHODtpe =>
+ val restpe = readTypeRef();
+ ImplicitMethodType(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 of " + classRoot.name + " at " + readIndex + "; " + msg);
+
+ private class LazyTypeRef(i: int) extends LazyType {
+ private val definedAtRun = currentRun;
+ override def complete(sym: Symbol): unit = {
+ val tp = at(i, readType);
+ sym setInfo tp;
+ if (currentRun != definedAtRun) tp.complete(sym)
+ }
+ override def load(sym: Symbol): unit = complete(sym)
+ }
+
+ private class LazyTypeRefAndAlias(i: int, j: int) extends LazyTypeRef(i) {
+ override def complete(sym: Symbol): unit = {
+ super.complete(sym);
+ sym.asInstanceOf[TermSymbol].setAlias(at(j, readSymbol));
+ }
+ }
+ }
+}