diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/symtab')
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)); + } + } + } +} |