From 4177daab2f54bdb20c71f623296a8bb32616fd12 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 13 Feb 2003 14:41:36 +0000 Subject: Initial version. --- sources/scalac/symtab/Symbol.java | 1291 +++++++++++++++++++++++++++++++++++++ 1 file changed, 1291 insertions(+) create mode 100644 sources/scalac/symtab/Symbol.java (limited to 'sources/scalac/symtab/Symbol.java') 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 ""; + if (isAnonymousClass()) return "