summaryrefslogtreecommitdiff
path: root/sources/scalac/symtab/Symbol.java
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2003-02-13 14:41:36 +0000
committerMartin Odersky <odersky@gmail.com>2003-02-13 14:41:36 +0000
commit4177daab2f54bdb20c71f623296a8bb32616fd12 (patch)
tree23f08b43f3758e825d5965b336030603a65bbcf7 /sources/scalac/symtab/Symbol.java
parent33d6e170c97ca7b2f991896a0729941a7240b6d6 (diff)
downloadscala-4177daab2f54bdb20c71f623296a8bb32616fd12.tar.gz
scala-4177daab2f54bdb20c71f623296a8bb32616fd12.tar.bz2
scala-4177daab2f54bdb20c71f623296a8bb32616fd12.zip
Initial version.
Diffstat (limited to 'sources/scalac/symtab/Symbol.java')
-rw-r--r--sources/scalac/symtab/Symbol.java1291
1 files changed, 1291 insertions, 0 deletions
diff --git a/sources/scalac/symtab/Symbol.java b/sources/scalac/symtab/Symbol.java
new file mode 100644
index 0000000000..f13192848b
--- /dev/null
+++ b/sources/scalac/symtab/Symbol.java
@@ -0,0 +1,1291 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+**
+** $Id$
+\* */
+
+//todo check significance of JAVA flag.
+
+package scalac.symtab;
+
+import scalac.ApplicationError;
+import scalac.Global;
+import scalac.PhaseDescriptor;
+import scalac.util.ArrayApply;
+import scalac.util.Name;
+import scalac.util.Names;
+import scalac.util.NameTransformer;
+import scalac.util.Position;
+import scalac.util.Debug;
+import scalac.symtab.classfile.*;
+
+
+public abstract class Symbol implements Modifiers, Kinds {
+
+ /** An empty symbol array */
+ public static final Symbol[] EMPTY_ARRAY = new Symbol[0];
+
+ /** An empty array of symbol arrays */
+ public static final Symbol[][] EMPTY_ARRAY_ARRAY = new Symbol[0][];
+
+ /** The error symbol */
+ public static final ErrorSymbol ERROR = new ErrorSymbol();
+
+ /** The absent symbol */
+ public static final NoSymbol NONE = new NoSymbol();
+
+// Fields -------------------------------------------------------------
+
+ /** The kind of the symbol */
+ public int kind;
+
+ /** The position of the symbol */
+ public int pos;
+
+ /** The name of the symbol */
+ public Name name;
+
+ /** The modifiers of the symbol */
+ public int flags;
+
+ /** The owner of the symbol */
+ private Symbol owner;
+
+ /** The infos of the symbol */
+ private TypeIntervalList infos = TypeIntervalList.EMPTY;
+
+// Constructors -----------------------------------------------------------
+
+ /** Generic symbol constructor */
+ public Symbol(int kind, int pos, Name name, Symbol owner, int flags) {
+ assert (!isTerm() || !name.isTypeName()) && (!isType() || name.isTypeName());
+
+ this.kind = kind;
+ this.pos = pos;
+ this.name = name;
+ this.owner = owner;
+ this.flags = flags & ~(INITIALIZED | LOCKED); // safety first
+ }
+
+ /** Return a fresh symbol with the same fields as this one.
+ */
+ public abstract Symbol cloneSymbol();
+
+ /** copy all fields to `sym'
+ */
+ public void copyTo(Symbol sym) {
+ sym.kind = kind;
+ sym.pos = pos;
+ sym.name = name;
+ sym.flags = flags;
+ sym.owner = owner;
+ sym.infos = infos;
+ }
+
+// Setters ---------------------------------------------------------------
+
+ /** Set the mangled name of this Symbol */
+ public Symbol setMangledName(Name name) {
+ throw new ApplicationError("illegal operation on " + getClass());
+ }
+
+ /** Set owner */
+ public Symbol setOwner(Symbol owner) {
+ this.owner = owner;
+ return this;
+ }
+
+ /** Set information, except if symbol is both initialized and locked.
+ */
+ public Symbol setInfo(Type info) {
+ return setInfo(info, currentPhaseId());
+ }
+
+ public Symbol setInfo(Type info, int limit) {
+ if ((flags & (INITIALIZED | LOCKED)) != (INITIALIZED | LOCKED)) {
+ if (infos == TypeIntervalList.EMPTY)
+ infos = new TypeIntervalList(TypeIntervalList.EMPTY);
+ infos.limit = limit;
+ infos.info = info;
+ }
+ return this;
+ }
+
+ /** Set type -- this is an alias for setInfo(Type info) */
+ public Symbol setType(Type info) { return setInfo(info); }
+
+ public Symbol updateInfo(Type info) {
+ // Global.instance.currentPhase.setInfo(this, info);
+ if (infos.limit <= Global.instance.currentPhase.id) {
+ infos = new TypeIntervalList(infos);
+ infos.limit = Global.instance.currentPhase.id + 1;
+ } else {
+ assert infos.limit == Global.instance.currentPhase.id + 1 : this;
+ }
+ infos.info = info;
+ return this;
+ }
+
+// Symbol classification ----------------------------------------------------
+
+ /** Does this symbol denote a type? */
+ public final boolean isType() {
+ return kind == TYPE || kind == CLASS || kind == ALIAS;
+ }
+
+ /** Does this symbol denote a term? */
+ public final boolean isTerm() {
+ return kind == VAL;
+ }
+
+ /** Does this symbol denote a value? */
+ public final boolean isValue() {
+ return kind == VAL && !(isModule() && isJava()) && !isPackage();
+ }
+
+ /** Does this symbol denote a variable? */
+ public final boolean isVariable() {
+ return kind == VAL && (flags & MUTABLE) != 0;
+ }
+
+ /** Does this symbol denote a method?
+ */
+ public final boolean isInitializedMethod() {
+ if (infos.limit < 0) return false;
+ switch (rawInfo()) {
+ case MethodType(_, _):
+ case PolyType(_, _): return true;
+ default: return false;
+ }
+ }
+
+ public final boolean isMethod() {
+ initialize();
+ return isInitializedMethod();
+ }
+
+ /* Does this symbol denote an anonymous class? */
+ public final boolean isAnonymousClass() {
+ return kind == CLASS &&
+ (name == Names.EMPTY.toTypeName() ||
+ name == Names.ANON_CLASS_NAME.toTypeName());
+ }
+
+ /** Does this symbol denote the root class or root module?
+ */
+ public final boolean isRoot() {
+ return this.moduleClass() == Global.instance.definitions.ROOT_CLASS;
+ }
+
+ /** Does this symbol denote something loaded from a Java class? */
+ public final boolean isJava() {
+ return (flags & JAVA) != 0;
+ }
+
+ /** Does this symbol denote a Java package? */
+ public final boolean isPackage() {
+ return (flags & PACKAGE) != 0;
+ }
+
+ /** Does this symbol denote a module? */
+ public final boolean isModule() {
+ return kind == VAL && (flags & MODUL) != 0;
+ }
+
+ /** Does this symbol denote a module? */
+ public final boolean isModuleClass() {
+ return kind == CLASS && (flags & MODUL) != 0;
+ }
+
+ /** Does this symbol denote a module? */
+ public final boolean isClass() {
+ return kind == CLASS;
+ }
+
+ /** Does this symbol denote a case class?
+ */
+ public final boolean isCaseClass() {
+ return kind == CLASS && (flags & CASE) != 0;
+ }
+
+ /** Does this symbol denote a uniform (i.e. parameterless) class? */
+ public final boolean isTrait() {
+ return kind == CLASS && (flags & TRAIT) != 0;
+ }
+
+ /** Does this class symbol denote a compound type symbol?
+ */
+ public final boolean isCompoundSym() {
+ return name == Names.COMPOUND_NAME.toTypeName();
+ }
+
+ /** Does this symbol denote an interface? */
+ public final boolean isInterface() {
+ return (flags & INTERFACE) != 0;
+ }
+
+ /** Does this symbol denote a static member? */
+ public final boolean isStatic() {
+ return (flags & STATIC) != 0;
+ }
+
+ /** Is this symbol locally defined? I.e. not a member of a class or module */
+ public final boolean isLocal() {
+ return owner.kind == VAL && !owner.isPrimaryConstructor();
+ }
+
+ /** Is this symbol a parameter? Includes type parameters of methods.
+ */
+ public final boolean isParameter() {
+ return (flags & PARAM) != 0;
+ }
+
+ /** Is this symbol a def parameter?
+ */
+ public final boolean isDefParameter() {
+ return (flags & (PARAM | DEF)) == (PARAM | DEF);
+ }
+
+ /** 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 class
+ */
+ public final boolean isLocalClass() {
+ return kind == CLASS &&
+ !isPackage() &&
+ (name == Names.EMPTY.toTypeName() ||
+ owner.isValue() ||
+ owner.isLocalClass());
+ }
+
+ /** Is this symbol a constructor? */
+ public final boolean isConstructor() {
+ return name.isConstrName();
+ }
+
+ /** Is this symbol the primary constructor of a type? */
+ public final boolean isPrimaryConstructor() {
+ return isConstructor() && this == constructorClass().constructor();
+ }
+
+ public boolean isGenerated() {
+ return name.pos((byte)'$') < name.length();
+ }
+
+ /** Symbol was preloaded from package
+ */
+ public boolean isPreloaded() {
+ return owner.isPackage() && pos == Position.NOPOS;
+ }
+
+// Symbol names ----------------------------------------------------------------
+
+ /** Get the fully qualified name of this Symbol
+ * (this is always a normal name, never a type name)
+ */
+ public Name fullName() {
+ return name.toTermName();
+ }
+
+ /** Get the mangled name of this Symbol
+ * (this is always a normal name, never a type name)
+ */
+ public Name mangledName() {
+ return name.toTermName();
+ }
+
+ /** Get the fully qualified mangled name of this Symbol */
+ public Name mangledFullName() {
+ return fullName().replace((byte)'.', (byte)'$');
+ }
+
+// Acess to related symbols -----------------------------------------------------
+
+ /** Get type parameters */
+ public Symbol[] typeParams() {
+ return EMPTY_ARRAY;
+ }
+
+ /** Get primary constructor of class */
+ public Symbol constructor() {
+ return NONE;
+ }
+
+ /** Get module associated with class */
+ public Symbol module() {
+ return NONE;
+ }
+
+ /** Get owner */
+ public Symbol owner() {
+ return owner;
+ }
+
+ /** Get owner, but if owner is primary constructor of a class,
+ * get class symbol instead. This is useful for type parameters
+ * and value parameters in classes which have the primary constructor
+ * as owner.
+ */
+ public Symbol classOwner() {
+ Symbol owner = owner();
+ Symbol clazz = owner.constructorClass();
+ if (clazz.constructor() == owner) return clazz;
+ else return owner;
+ }
+
+ /** The next enclosing class */
+ public Symbol enclClass() {
+ return owner().enclClass();
+ }
+
+ /** The top-level class enclosing `sym'
+ */
+ Symbol enclToplevelClass() {
+ Symbol sym = this;
+ while (sym.kind == VAL ||
+ (sym.kind == CLASS && !sym.owner().isPackage())) {
+ sym = sym.owner();
+ }
+ return sym;
+ }
+
+ /* If this is a constructor, return the class it constructs.
+ * Otherwise return the symbol itself.
+ */
+ public Symbol constructorClass() {
+ return this;
+ }
+
+ /* If this is a module, return its class.
+ * Otherwise return the symbol itself.
+ */
+ public Symbol moduleClass() {
+ return this;
+ }
+
+ /** The symbol accessed by this accessor function.
+ */
+ public Symbol accessed() {
+ assert (flags & ACCESSOR) != 0;
+ Name name1 = name;
+ if (name1.endsWith(Names._EQ))
+ name1 = name1.subName(0, name1.length() - Names._EQ.length());
+ return owner.info().lookup(Name.fromString(name1 + "$"));
+ }
+
+ /** The members of this class or module symbol
+ */
+ public Scope members() {
+ return info().members();
+ }
+
+// Symbol types --------------------------------------------------------------
+
+ /** Was symbol's type updated during phase `id'?
+ */
+ public boolean isUpdated(int id) {
+ return infos.limit >= id;
+ }
+
+ /** the current phase id, or the id after analysis, whichever is larger.
+ */
+ int currentPhaseId() {
+ int id = Global.instance.currentPhase.id;
+ if (id > Global.instance.POST_ANALYZER_PHASE_ID)
+ id = Global.instance.POST_ANALYZER_PHASE_ID;
+ return id;
+ }
+
+ /** Is this symbol initialized? */
+ public final boolean isInitialized() {
+ return (flags & INITIALIZED) != 0;
+ }
+
+ /** Initialize the symbol */
+ public final Symbol initialize() {
+ info();
+ return this;
+ }
+
+ /** Get info; This is:
+ * for a term symbol, its type
+ * for a type variable, its bound
+ * for a type alias, its right-hand side
+ * for a class symbol, the compound type consisting of
+ * its baseclasses and members.
+ */
+ public Type info() {
+ if ((flags & INITIALIZED) == 0) {
+ int id = currentPhaseId();
+ Type info = rawInfoAt(id);
+ assert info != null : this;
+
+ if ((flags & LOCKED) != 0) {
+ setInfo(Type.ErrorType);
+ flags |= INITIALIZED;
+ throw new CyclicReference(this, info);
+ }
+ flags |= LOCKED;
+ //System.out.println("completing " + this);//DEBUG
+ info.complete(this);
+ flags = flags & ~LOCKED;
+ if (info instanceof SourceCompleter && (flags & SNDTIME) == 0) {
+ flags |= SNDTIME;
+ return info();
+ } else {
+ assert !(rawInfoAt(id) instanceof Type.LazyType) : this;
+ flags |= INITIALIZED;
+ }
+ //System.out.println("done: " + this);//DEBUG
+ }
+ return rawInfoAt(Global.instance.currentPhase.id);
+ }
+
+ /** Get info at phase #id
+ */
+ public Type infoAt(int id) {
+ info();
+ return rawInfoAt(id);
+ }
+
+ /** get info at phase #id, without forcing lazy types.
+ */
+ private Type rawInfoAt(int id) {
+ int nextid = infos.limit;
+ assert infos != TypeIntervalList.EMPTY : this;
+ if (nextid < id) {
+ do {
+ Type newInfo =
+ Global.instance.phases[nextid].transformInfo(this, infos.info);
+ if (newInfo != infos.info) {
+ infos = new TypeIntervalList(infos);
+ infos.info = newInfo;
+ }
+ nextid++;
+ infos.limit = nextid;
+ } while (nextid < id);
+ return infos.info;
+ } else {
+ TypeIntervalList infos1 = infos;
+ while (infos1.prev.limit >= id) {
+ infos1 = infos1.prev;
+ }
+ return infos1.info;
+ }
+ }
+
+ public Type rawInfo() {
+ return rawInfoAt(Global.instance.currentPhase.id);
+ }
+
+ /** The type of a symbol is:
+ * for a type symbol, the type corresponding to the symbol itself
+ * for a term symbol, its usual type
+ */
+ public Type type() {
+ return info();
+ }
+
+ /** The type at phase #id
+ */
+ public Type typeAt(int id) {
+ return infoAt(id);
+ }
+
+ /** The types of these symbols as an array.
+ */
+ static public Type[] type(Symbol[] syms) {
+ Type[] tps = new Type[syms.length];
+ for (int i = 0; i < syms.length; i++)
+ tps[i] = syms[i].type();
+ return tps;
+ }
+
+ /** Get this.type corresponding to this symbol
+ */
+ public Type thisType() {
+ return Type.localThisType;
+ }
+
+ public Type typeOfThis() {
+ return Type.localThisType;
+ }
+
+ /** A total ordering between symbols that refines the class
+ * inheritance graph (i.e. subclass.isLess(superclass) always holds).
+ */
+ public boolean isLess(Symbol that) {
+ if (this == that) return false;
+ int diff;
+ if (this.isType()) {
+ if (that.isType()) {
+ diff = this.closure().length - that.closure().length;
+ if (diff > 0) return true;
+ if (diff < 0) return false;
+ } else {
+ return true;
+ }
+ } else if (that.isType()) {
+ return false;
+ }
+
+ diff = that.mangledName().index - this.mangledName().index;
+ if (diff > 0) return true;
+ if (diff < 0) return false;
+
+ diff = that.mangledFullName().index - this.mangledFullName().index;
+ if (diff > 0) return true;
+ if (diff < 0) return false;
+
+ throw new ApplicationError(
+ "Giving up: can't order two incarnations of class " +
+ this.mangledFullName());
+ }
+
+ /** Return the symbol's type itself followed by all its direct and indirect
+ * base types, sorted by isLess(). Overridden for class symbols.
+ */
+ public Type[] closure() {
+ return info().closure();
+ }
+
+ /** Return position of `c' in the closure of this type; -1 if not there.
+ */
+ public int closurePos(Symbol c) {
+ if (this == c) return 0;
+ if (c.isCompoundSym()) return -1;
+ Type[] closure = closure();
+ int lo = 0;
+ int hi = closure.length - 1;
+ while (lo <= hi) {
+ int mid = (lo + hi) / 2;
+ Symbol clsym = closure[mid].symbol();
+ if (c == clsym) return mid;
+ else if (c.isLess(clsym)) hi = mid - 1;
+ else if (clsym.isLess(c)) lo = mid + 1;
+ else throw new ApplicationError();
+ }
+ return -1;
+ }
+
+ Type baseType(Symbol sym) {
+ int i = closurePos(sym);
+ if (i >= 0) return closure()[i];
+ else return Type.NoType;
+ }
+
+ /** Is this class a subclass of `c'? I.e. does it have a type instance
+ * of `c' as indirect base class?
+ */
+ public boolean isSubClass(Symbol c) {
+ return this == c || c.kind == Kinds.ERROR || closurePos(c) >= 0;
+ }
+
+// ToString -------------------------------------------------------------------
+
+ /** String representation of symbol's simple name.
+ * Translates expansions of operators back to operator symbol. E.g.
+ * $eq => =.
+ */
+ public String nameString() {
+ return NameTransformer.decode(name).toString();
+ }
+
+ /** String representation of symbol's full name.
+ * Translates expansions of operators back to operator symbol. E.g.
+ * $eq => =.
+ */
+ public String fullNameString() {
+ return NameTransformer.decode(fullName()).toString();
+ }
+
+ public String idString() {
+ if (Global.instance.uniqid &&
+ (kind == TYPE || Global.instance.debug))
+ return "#" + Global.instance.uniqueID.id(this);
+ else return "";
+ }
+
+ /** String representation, including symbol's kind
+ * e.g., "class Foo", "function Bar".
+ */
+ public String toString() {
+ if (isRoot()) return "<root package>";
+ if (isAnonymousClass()) return "<template>";
+ String kstr = kindString();
+ String str;
+ if (kstr.length() == 0) str = fullNameString();
+ else str = kstr + " " + fullNameString();
+ return str + idString();
+ }
+
+ /** String representation of location.
+ */
+ public String locationString() {
+ if (owner.kind == CLASS && !owner.isAnonymousClass())
+ return " in " + owner;
+ else
+ return "";
+ }
+
+ /** String representation of definition.
+ */
+ public String defString() {
+ String inner;
+ if (kind == CLASS) inner = " extends ";
+ else if (kind == TYPE) inner = " <: ";
+ else if (kind == ALIAS) inner = " = ";
+ else inner = " : ";
+ return
+ (isParameter() ? "" : defKeyword() + " ") +
+ nameString() + idString() + inner +
+ (rawInfoAt(Global.instance.POST_ANALYZER_PHASE_ID)
+ instanceof Type.LazyType ? "?" : info());
+ }
+
+ public static String[] defString(Symbol[] defs) {
+ String[] strs = new String[defs.length];
+ for (int i = 0; i < defs.length; i++)
+ strs[i] = defs[i].defString();
+ return strs;
+ }
+
+ /** String representation of kind */
+ public String kindString() {
+ switch (kind) {
+ case CLASS:
+ if ((flags & TRAIT) != 0)
+ return "trait";
+ else if ((flags & MODUL) != 0 && Global.instance.debug)
+ return "module class";
+ else
+ return "class";
+ case TYPE:
+ case ALIAS:
+ return "type";
+ case VAL:
+ if (isVariable()) return "variable";
+ else if (isModule()) return "module";
+ else if (isConstructor()) return "constructor";
+ else if (isInitializedMethod()) return "method";
+ else return "value";
+ default: return "";
+ }
+ }
+
+ /** Definition keyword of kind
+ */
+ public String defKeyword() {
+ switch (kind) {
+ case CLASS: if ((flags & TRAIT) != 0) return "trait"; else return "class";
+ case TYPE:
+ case ALIAS: return "type";
+ case VAL:
+ if (isVariable()) return "var";
+ else if (isModule()) return "module";
+ else if (isInitializedMethod()) return "def";
+ else return "val";
+ default: return "";
+ }
+ }
+
+// Overloading and Overriding -------------------------------------------
+
+ /** Add another overloaded alternative to this symbol.
+ */
+ public Symbol overloadWith(Symbol that) {
+ assert isTerm() : this;
+ assert this.name == that.name : this + " " + that;
+ assert this.owner == that.owner : this + " " + that;
+ assert (this.flags & that.flags & JAVA) != 0 ||
+ (this.flags & (SOURCEFLAGS | JAVA) & ~ACCESSFLAGS) ==
+ (that.flags & (SOURCEFLAGS | JAVA) & ~ACCESSFLAGS) : this + " " + that;
+ TermSymbol overloaded = new TermSymbol(
+ pos, name, owner,
+ ((this.flags | that.flags) & (SOURCEFLAGS | JAVA) & ~ACCESSFLAGS) |
+ (this.flags & that.flags & ACCESSFLAGS));
+ overloaded.setInfo(new LazyOverloadedType(this, that));
+ return overloaded;
+ }
+
+ /** A lazy type which, when forced computed the overloaded type
+ * of symbols `sym1' and `sym2'. It also checks that this type is well-formed.
+ */
+ private static class LazyOverloadedType extends Type.LazyType {
+ Symbol sym1;
+ Symbol sym2;
+ LazyOverloadedType(Symbol sym1, Symbol sym2) {
+ this.sym1 = sym1;
+ this.sym2 = sym2;
+ }
+ private Symbol[] alts(Symbol sym) {
+ if (sym == null) return Symbol.EMPTY_ARRAY;
+ switch (sym.type()) {
+ case OverloadedType(Symbol[] alts, _): return alts;
+ default: return new Symbol[]{sym};
+ }
+ }
+ private Type[] alttypes(Symbol sym) {
+ if (sym == null) return Type.EMPTY_ARRAY;
+ switch (sym.type()) {
+ case OverloadedType(_, Type[] alttypes): return alttypes;
+ default: return new Type[]{sym.type()};
+ }
+ }
+ public void complete(Symbol overloaded) {
+ if (sym1 != null) sym1.initialize();
+ if (sym2 != null) sym2.initialize();
+
+ Symbol[] alts1 = alts(sym1);
+ Symbol[] alts2 = alts(sym2);
+ Symbol[] alts3 = new Symbol[alts1.length + alts2.length];
+ System.arraycopy(alts1, 0, alts3, 0, alts1.length);
+ System.arraycopy(alts2, 0, alts3, alts1.length, alts2.length);
+
+ Type[] alttypes1 = alttypes(sym1);
+ Type[] alttypes2 = alttypes(sym2);
+ Type[] alttypes3 = new Type[alttypes1.length + alttypes2.length];
+ System.arraycopy(alttypes1, 0, alttypes3, 0, alttypes1.length);
+ System.arraycopy(alttypes2, 0, alttypes3, alttypes1.length, alttypes2.length);
+ overloaded.setInfo(Type.OverloadedType(alts3, alttypes3));
+ }
+ }
+
+ /** All the alternatives of this symbol if it's overloaded, the
+ * symbol alone otherwise.
+ */
+ public Symbol[] alternatives() {
+ switch (type()) {
+ case OverloadedType(Symbol[] alts, _): return alts;
+ default: return new Symbol[]{this};
+ }
+ }
+
+ /** The symbol which is overridden by this symbol in base class `base'
+ * `base' must be a superclass of this.owner().
+ */
+ public Symbol overriddenSymbol(Type base) {
+ Symbol sym1 = base.lookupNonPrivate(name);
+ if (sym1.kind == Kinds.NONE || (sym1.flags & STATIC) != 0) {
+ return Symbol.NONE;
+ } else {
+ //System.out.println(this + ":" + this.type() + locationString() + " overrides? " + sym1 + sym1.type() + sym1.locationString()); //DEBUG
+
+ Type symtype = owner.thisType().memberType(this);
+ //todo: try whether we can do: this.type(); instead
+ Type sym1type = owner.thisType().memberType(sym1);
+ switch (sym1type) {
+ case OverloadedType(Symbol[] alts, Type[] alttypes):
+ for (int i = 0; i < alts.length; i++) {
+ if (symtype.isSameAs(alttypes[i])) return alts[i];
+ }
+ return Symbol.NONE;
+ default:
+ if (symtype.isSameAs(sym1type)) return sym1;
+ else {
+ System.out.println(this + locationString() + " does not override " + sym1 + sym1.locationString() + ", since " + symtype + " # " + sym1type);//DEBUG
+ return Symbol.NONE;
+ }
+ }
+ }
+ }
+}
+
+/** A class for term symbols
+ */
+public class TermSymbol extends Symbol {
+
+ private Symbol clazz;
+
+ /** Constructor */
+ public TermSymbol(int pos, Name name, Symbol owner, int flags) {
+ super(VAL, pos, name, owner, flags);
+ }
+
+ public static TermSymbol newConstructor(Symbol clazz, int flags) {
+ TermSymbol sym = new TermSymbol(
+ clazz.pos, clazz.name.toConstrName(), clazz.owner(),
+ flags | FINAL);
+ sym.clazz = clazz;
+ return sym;
+ }
+
+ public static TermSymbol newJavaConstructor(Symbol clazz) {
+ return newConstructor(clazz, clazz.flags & (ACCESSFLAGS | QUALIFIED | JAVA));
+ }
+
+ public static TermSymbol newModule(int pos, Name name, Symbol owner, int flags) {
+ TermSymbol sym = new TermSymbol(pos, name, owner, flags | MODUL | FINAL);
+ Symbol clazz = new ClassSymbol(
+ pos, name.toTypeName(), owner, flags | MODUL | FINAL, sym);
+ Type clazztype = Type.TypeRef(owner.thisType(), clazz, Type.EMPTY_ARRAY);
+ clazz.constructor().setInfo(Type.MethodType(Symbol.EMPTY_ARRAY, clazztype));
+ sym.clazz = clazz;
+ sym.setInfo(clazztype);
+ return sym;
+ }
+
+ /** Constructor for companion modules to classes, which need to be completed.
+ */
+ public static TermSymbol newCompanionModule(Symbol clazz, int flags, Type.LazyType parser) {
+ TermSymbol sym = newModule(Position.NOPOS, clazz.name.toTermName(), clazz.owner(),
+ FINAL | flags);
+ sym.clazz.setInfo(parser);
+ return sym;
+ }
+
+ /** Java package module constructor
+ */
+ public static TermSymbol newJavaPackageModule(Name name, Symbol owner, Type.LazyType parser) {
+ TermSymbol sym = newModule(Position.NOPOS, name, owner, JAVA | PACKAGE);
+ sym.clazz.flags |= SYNTHETIC;
+ sym.clazz.setInfo(parser);
+ return sym;
+ }
+
+ /** Get this.type corresponding to this class or module
+ */
+ public Type thisType() {
+ if ((flags & MODUL) != 0) return moduleClass().thisType();
+ else return Type.localThisType;
+ }
+ /** Get the fully qualified name of this Symbol */
+ public Name fullName() {
+ if ((flags & MODUL) != 0) return moduleClass().fullName();
+ else return super.fullName();
+ }
+
+ /** Return a fresh symbol with the same fields as this one.
+ */
+ public Symbol cloneSymbol() {
+ assert !isPrimaryConstructor() : Debug.show(this);
+ TermSymbol other;
+ if (isModule()) {
+ other = newModule(pos, name, owner(), flags);
+ } else {
+ other = new TermSymbol(pos, name, owner(), flags);
+ other.clazz = clazz;
+ }
+ other.setInfo(info());
+ return other;
+ }
+
+ public Symbol constructorClass() {
+ return isConstructor() ? clazz : this;
+ }
+
+ public Symbol moduleClass() {
+ return (flags & MODUL) != 0 ? clazz : this;
+ }
+}
+
+/** A class for (abstract and alias) type symbols. It has ClassSymbol as a subclass.
+ */
+public class TypeSymbol extends Symbol {
+
+ /** A cache for closures
+ */
+ private ClosureIntervalList closures = ClosureIntervalList.EMPTY;
+
+ /** The symbol's type template */
+ private Type template;
+
+ /** The primary constructor of this type */
+ public final Symbol constructor;
+
+ /** Constructor */
+ public TypeSymbol(int kind, int pos, Name name, Symbol owner, int flags) {
+ super(kind, pos, name, owner, flags);
+ this.constructor = TermSymbol.newConstructor(this, flags);
+ if (kind == TYPE) { // provide a constructor type
+ this.constructor().setInfo(
+ Type.PolyType(Symbol.EMPTY_ARRAY, Type.NoType));
+ }
+ }
+
+ /** Return a fresh symbol with the same fields as this one.
+ */
+ public Symbol cloneSymbol() {
+ if (Global.instance.debug) System.out.println("cloning " + this + this.locationString());
+ TypeSymbol other = new TypeSymbol(kind, pos, name, owner(), flags);
+ other.setInfo(info());
+ other.constructor.setInfo(constructor.info());
+ return other;
+ }
+
+ /** Get self type */
+ public Type type() {
+ if (template == null || template.typeArgs().length != typeParams().length) {
+ template = Type.TypeRef(
+ owner().thisType(), this, type(typeParams()));
+ }
+ return template;
+ }
+
+ //todo: needed?
+ public Type typeAt(int id) {
+ return type();
+ }
+
+ /** Get type parameters */
+ public Symbol[] typeParams() {
+ return constructor.info().typeParams();
+ }
+
+ /** Get primary constructor */
+ public Symbol constructor() {
+ return constructor;
+ }
+
+ public Type[] closure() {
+ if (kind == ALIAS) return info().symbol().closure();
+ int id = Global.instance.currentPhase.id;
+ if (closures.limit < id) {
+ if (id == 0 || changes(closureAt(id - 1))) {
+ closures = new ClosureIntervalList(closures);
+ closures.limit = id;
+ computeClosure();
+ } else {
+ closures.limit = id;
+ }
+ return closures.closure;
+ } else {
+ ClosureIntervalList closures1 = closures;
+ while (closures1.prev.limit >= id) {
+ closures1 = closures1.prev;
+ }
+ return closures1.closure;
+ }
+ }
+
+ //todo: needed?
+ private Type[] closureAt(int id) {
+ PhaseDescriptor savedPhase = Global.instance.currentPhase;
+ Global.instance.currentPhase = Global.instance.phases[id];
+ Type[] c = closure();
+ Global.instance.currentPhase = savedPhase;
+ return c;
+ }
+
+ private boolean changes(Type[] closure) {
+ for (int i = 0; i < closure.length; i++) {
+ Symbol c = closure[i].symbol();
+ if (c.infoAt(Global.instance.currentPhase.id - 1) != c.info())
+ return true;
+ }
+ return false;
+ }
+
+ private static Type[] BAD_CLOSURE = new Type[0];
+
+ /** Return the type itself followed by all direct and indirect
+ * base types of this type, sorted by isLess().
+ */
+ private void computeClosure() {
+ assert closures.closure != BAD_CLOSURE : this;
+ closures.closure = BAD_CLOSURE; // to catch cycles.
+ SymSet closureClassSet = inclClosureBases(SymSet.EMPTY, this);
+ Symbol[] closureClasses = new Symbol[closureClassSet.size() + 1];
+ closureClasses[0] = this;
+ closureClassSet.copyToArray(closureClasses, 1);
+ //System.out.println(ArrayApply.toString(closureClasses));//DEBUG
+ closures.closure = Symbol.type(closureClasses);
+ //System.out.println(ArrayApply.toString(closures.closure));//DEBUG
+ adjustType(type());
+ //System.out.println("closure(" + this + ") at " + Global.instance.currentPhase.name() + " = " + ArrayApply.toString(closures.closure));//DEBUG
+ }
+ //where
+
+ private SymSet inclClosureBases(SymSet set, Symbol c) {
+ Type[] parents = c.type().parents();
+ for (int i = 0; i < parents.length; i++) {
+ set = inclClosure(set, parents[i].symbol());
+ }
+ return set;
+ }
+
+ private SymSet inclClosure(SymSet set, Symbol c) {
+ Symbol c1 = c;
+ while (c1.kind == ALIAS) c1 = c1.info().symbol();
+ return inclClosureBases(set.incl(c1), c1);
+ }
+
+ void adjustType(Type tp) {
+ Type tp1 = tp.unalias();
+ int pos = closurePos(tp1.symbol());
+ assert pos >= 0 : this + " " + tp1 + " " + tp1.symbol();
+ closures.closure[pos] = tp1;
+ Type[] parents = tp1.parents();
+ for (int i = 0; i < parents.length; i++) {
+ adjustType(parents[i]);
+ }
+ }
+}
+
+/** A class for class symbols. It has JavaClassSymbol as a subclass.
+ */
+public class ClassSymbol extends TypeSymbol {
+
+ /** The mangled class name */
+ private Name mangled;
+
+ /** The module belonging to the class. This means:
+ * For Java classes, its statics parts.
+ * For module classes, the corresponding module.
+ * For other classes, null.
+ */
+ private Symbol module = NONE;
+
+ /** Principal Constructor for module classes and classes with static members.
+ */
+ public ClassSymbol(int pos, Name name, Symbol owner, int flags) {
+ super(CLASS, pos, name, owner, flags);
+ this.mangled = name;
+ }
+
+ /** Constructor for module classes and classes with static members.
+ */
+ public ClassSymbol(int pos, Name name, Symbol owner, int flags, Symbol module) {
+ this(pos, name, owner, flags);
+ this.module = module;
+ }
+
+ /** Constructor for classes to load as source files
+ */
+ public ClassSymbol(Name name, Symbol owner, SourceCompleter parser) {
+ this(Position.NOPOS, name, owner, 0);
+ this.module = TermSymbol.newCompanionModule(this, 0, parser);
+ this.mangled = name;
+ this.setInfo(parser);
+ }
+
+ /** Constructor for classes to load as class files.
+ */
+ public ClassSymbol(Name name, Symbol owner, ClassParser parser) {
+ super(CLASS, Position.NOPOS, name, owner, JAVA);
+ this.module = TermSymbol.newCompanionModule(this, JAVA, parser.staticsParser(this));
+ this.mangled = name;
+ this.setInfo(parser);
+ }
+
+ /** Return a fresh symbol with the same fields as this one.
+ */
+ public Symbol cloneSymbol() {
+ ClassSymbol other = new ClassSymbol(pos, name, owner(), flags);
+ other.setInfo(info());
+ other.constructor.setInfo(constructor.info());
+ other.mangled = mangled;
+ other.module = module;
+ return other;
+ }
+
+ /** Get module */
+ public Symbol module() {
+ return module;
+ }
+
+ /** Set the mangled name of this Symbol */
+ public Symbol setMangledName(Name name) {
+ this.mangled = name;
+ return this;
+ }
+
+ /** Get the fully qualified name of this Symbol */
+ public Name fullName() {
+ if (owner().kind == CLASS && owner().name.length() != 0)
+ return Name.fromString(owner().fullName() + "." + name);
+ else
+ return name.toTermName();
+ }
+
+ /** Get the mangled name of this Symbol */
+ public Name mangledName() {
+ return mangled;
+ }
+
+ /** Get the fully qualified mangled name of this Symbol */
+ public Name mangledFullName() {
+ if (mangled == name) {
+ return fullName().replace((byte)'.', (byte)'$');
+ } else {
+ return Name.fromString(
+ enclToplevelClass().mangledFullName() + "$" + mangled);
+ }
+ }
+
+ private Type thistp = Type.ThisType(this);
+
+ public Type thisType() {
+ return thistp;
+ }
+
+ /** Return the next enclosing class */
+ public Symbol enclClass() {
+ return this;
+ }
+
+ public Symbol caseFieldAccessor(int index) {
+ assert (flags & CASE) != 0 : this;
+ Scope.SymbolIterator it = info().members().iterator();
+ Symbol sym = null;
+ for (int i = 0; i <= index; i++) {
+ do {
+ sym = it.next();
+ } while (sym.kind != VAL || (sym.flags & CASE) == 0);
+ }
+ //System.out.println(this + ", case field[" + index + "] = " + sym);//DEBUG
+ assert sym != null : this;
+ return sym;
+ }
+}
+
+/** A class for error symbols.
+ */
+public final class ErrorSymbol extends Symbol {
+
+ /** Constructor */
+ public ErrorSymbol() {
+ super(Kinds.ERROR, Position.NOPOS, Name.fromString("<error>"), null,
+ INITIALIZED);
+ this.setOwner(this);
+ this.setInfo(Type.ErrorType);
+ }
+
+ public Symbol cloneSymbol() {
+ return this;
+ }
+
+ /** Set the mangled name of this Symbol */
+ public Symbol mangled(Name name) {
+ return this;
+ }
+
+ /** Set owner */
+ public Symbol setOwner(Symbol owner) {
+ if (owner != this)
+ throw new ApplicationError("illegal operation on " + getClass());
+ return super.setOwner(owner);
+ }
+
+ /** Set type */
+ public Symbol setInfo(Type info) {
+ if (info != Type.ErrorType)
+ throw new ApplicationError("illegal operation on " + getClass());
+ return super.setInfo(info);
+ }
+
+ /** Get primary constructor */
+ public Symbol constructor() {
+ return TermSymbol.newConstructor(this, 0).setInfo(Type.ErrorType);
+ }
+
+ /** Return the next enclosing class */
+ public Symbol enclClass() {
+ return this;
+ }
+}
+
+/** The class of Symbol.NONE
+ */
+public final class NoSymbol extends Symbol {
+
+ /** Constructor */
+ public NoSymbol() {
+ super(Kinds.NONE, Position.NOPOS, Name.fromString("<none>"), null, INITIALIZED);
+ this.setInfo(Type.NoType);
+ this.setOwner(this);
+ }
+
+ /** Return a fresh symbol with the same fields as this one.
+ */
+ public Symbol cloneSymbol() {
+ return this;
+ }
+
+ /** Set the mangled name of this Symbol */
+ public Symbol mangled(Name name) {
+ throw new ApplicationError("illegal operation on " + getClass());
+ }
+
+ /** Set owner */
+ public Symbol setOwner(Symbol owner) {
+ if (owner != this)
+ throw new ApplicationError("illegal operation on " + getClass());
+ return super.setOwner(owner);
+ }
+
+ /** Set type */
+ public Symbol setInfo(Type info) {
+ if (info != Type.NoType)
+ throw new ApplicationError("illegal operation on " + getClass());
+ return super.setInfo(info);
+ }
+
+ /** Return the next enclosing class */
+ public Symbol enclClass() {
+ return this;
+ }
+
+ public Symbol owner() {
+ throw new ApplicationError();
+ }
+}
+
+/** A class for symbols generated in label definitions.
+ */
+public class LabelSymbol extends TermSymbol {
+
+ /** give as argument the symbol of the function that triggered
+ the creation of this label */
+ public LabelSymbol(Symbol f) {
+ super(f.pos, f.name, f, LABEL);
+ }
+}
+
+/** An exception for signalling cyclic references.
+ */
+public class CyclicReference extends Type.Error {
+ public Symbol sym;
+ public Type info;
+ public CyclicReference(Symbol sym, Type info) {
+ super("illegal cyclic reference involving " + sym);
+ this.sym = sym;
+ this.info = info;
+ }
+}
+
+/** A class for types indexed by phase numbers.
+ */
+class TypeIntervalList {
+ int limit;
+ Type info;
+ TypeIntervalList prev;
+ TypeIntervalList(TypeIntervalList prev) {
+ this.prev = prev;
+ }
+ static TypeIntervalList EMPTY = new TypeIntervalList(null);
+
+ static {
+ EMPTY.limit = -1;
+ }
+}
+
+/** A class for closures indexed by phase numbers.
+ */
+class ClosureIntervalList {
+ int limit;
+ Type[] closure;
+ ClosureIntervalList prev;
+ ClosureIntervalList(ClosureIntervalList prev) {
+ this.prev = prev;
+ }
+ static ClosureIntervalList EMPTY = new ClosureIntervalList(null);
+ static {
+ EMPTY.limit = -1;
+ }
+}
+