summaryrefslogtreecommitdiff
path: root/sources/scalac/symtab
diff options
context:
space:
mode:
Diffstat (limited to 'sources/scalac/symtab')
-rw-r--r--sources/scalac/symtab/Definitions.java421
-rw-r--r--sources/scalac/symtab/Kinds.java28
-rw-r--r--sources/scalac/symtab/Modifiers.java135
-rw-r--r--sources/scalac/symtab/NameMangler.java33
-rw-r--r--sources/scalac/symtab/Scope.java306
-rw-r--r--sources/scalac/symtab/SourceCompleter.java53
-rw-r--r--sources/scalac/symtab/SymSet.java89
-rw-r--r--sources/scalac/symtab/Symbol.java1291
-rw-r--r--sources/scalac/symtab/Type.java2353
-rw-r--r--sources/scalac/symtab/TypeTags.java47
-rw-r--r--sources/scalac/symtab/classfile/AttributeParser.java439
-rw-r--r--sources/scalac/symtab/classfile/ClassParser.java111
-rw-r--r--sources/scalac/symtab/classfile/ClassfileConstants.java57
-rw-r--r--sources/scalac/symtab/classfile/ClassfileParser.java239
-rw-r--r--sources/scalac/symtab/classfile/ConstantPool.java183
-rw-r--r--sources/scalac/symtab/classfile/JavaTypeCreator.java82
-rw-r--r--sources/scalac/symtab/classfile/JavaTypeFactory.java28
-rw-r--r--sources/scalac/symtab/classfile/PackageParser.java129
-rw-r--r--sources/scalac/symtab/classfile/Signatures.java122
19 files changed, 6146 insertions, 0 deletions
diff --git a/sources/scalac/symtab/Definitions.java b/sources/scalac/symtab/Definitions.java
new file mode 100644
index 0000000000..6d67edac42
--- /dev/null
+++ b/sources/scalac/symtab/Definitions.java
@@ -0,0 +1,421 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab;
+
+import scalac.*;
+import scalac.util.*;
+import scalac.symtab.classfile.*;
+import Type.*;
+
+public class Definitions {
+
+ /** the root module
+ */
+ public final Symbol ROOT;
+ public final Symbol ROOT_CLASS;
+ public final Type ROOT_TYPE;
+
+ /** the scala module
+ */
+ public final Symbol SCALA;
+ public final Symbol SCALA_CLASS;
+ public final Type SCALA_TYPE;
+
+ /** the java module
+ */
+ public final Symbol JAVA;
+ public final Symbol JAVA_CLASS;
+ public final Type JAVA_TYPE;
+
+ /** the java.lang module
+ */
+ public final Symbol JAVALANG;
+ public final Symbol JAVALANG_CLASS;
+ public final Type JAVALANG_TYPE;
+
+ /** the scala.runtime module
+ */
+ public final Symbol SCALARUNTIME;
+ public final Symbol SCALARUNTIME_CLASS;
+ public final Type SCALARUNTIME_TYPE;
+
+ /** the null value
+ */
+ public final Symbol NULL;
+
+ /** the scala.Any class
+ */
+ public final Symbol ANY_CLASS;
+ public final Type ANY_TYPE;
+
+ /** some methods of the scala.Any class
+ */
+ public final Symbol MATCH;
+ public final Symbol IS;
+ public final Symbol AS;
+ public final Symbol EQEQ;
+ public final Symbol BANGEQ;
+ public final Symbol TOSTRING;
+ public final Symbol HASHCODE;
+
+ /** a method of class java.lang.Throwable
+ */
+ public final Symbol THROW;
+
+ /** the scala.AnyVal class
+ */
+ public final Symbol ANYVAL_CLASS;
+ public final Type ANYVAL_TYPE;
+
+ /** the scala.AnyRef class
+ */
+ public final Symbol ANYREF_CLASS;
+ public final Type ANYREF_TYPE;
+
+ /** the java.lang.Object class
+ */
+ public final Symbol JAVA_OBJECT_CLASS;
+ public final Type JAVA_OBJECT_TYPE;
+
+ /** the scala.Object class
+ */
+ public final Symbol OBJECT_CLASS;
+ public final Type OBJECT_TYPE;
+
+ /** the primitive types
+ */
+ public final Symbol BYTE_CLASS;
+ public final Type BYTE_TYPE;
+ public final Symbol SHORT_CLASS;
+ public final Type SHORT_TYPE;
+ public final Symbol CHAR_CLASS;
+ public final Type CHAR_TYPE;
+ public final Symbol INT_CLASS;
+ public final Type INT_TYPE;
+ public final Symbol LONG_CLASS;
+ public final Type LONG_TYPE;
+ public final Symbol FLOAT_CLASS;
+ public final Type FLOAT_TYPE;
+ public final Symbol DOUBLE_CLASS;
+ public final Type DOUBLE_TYPE;
+ public final Symbol BOOLEAN_CLASS;
+ public final Type BOOLEAN_TYPE;
+ public final Symbol UNIT_CLASS;
+ public final Type UNIT_TYPE;
+
+ /** the array class
+ */
+ public final Symbol ARRAY_CLASS;
+
+ /** types from java.lang
+ */
+ public final Symbol JAVA_STRING_CLASS;
+ public final Type JAVA_STRING_TYPE;
+ public final Symbol JAVA_THROWABLE_CLASS;
+ public final Type JAVA_THROWABLE_TYPE;
+
+ /** types from scala
+ */
+ public final Symbol STRING_CLASS;
+ public final Type STRING_TYPE;
+
+ /** string concatenation pseudo-methods of classes scala.Any and
+ * java.lang.String
+ */
+ //public final Symbol ANY_PLUS_STRING;
+ public final Symbol STRING_PLUS_ANY;
+
+ /** members of class Boolean
+ */
+ private Symbol TRUE;
+ private Symbol FALSE;
+ private Symbol BARBAR;
+ private Symbol AMPAMP;
+
+ public Symbol TRUE () { loadBooleanMembers(); return TRUE ; }
+ public Symbol FALSE () { loadBooleanMembers(); return FALSE ; }
+ public Symbol BARBAR() { loadBooleanMembers(); return BARBAR; }
+ public Symbol AMPAMP() { loadBooleanMembers(); return AMPAMP; }
+
+ public Definitions(Global global) {
+ // a hack to make definitions accessible earlier to other
+ // components
+ global.definitions = this;
+ PackageParser pparser = new PackageParser(global);
+
+ // this is the root value; all top-level functions,
+ // modules etc. are a member of this value
+ ROOT = TermSymbol.newJavaPackageModule(
+ Names.EMPTY, Symbol.NONE, pparser);
+ ROOT_CLASS = ROOT.moduleClass();
+ // this is a prefix for all types inside of the anonymous package
+ ROOT_TYPE = ROOT_CLASS.thisType();
+
+ // the scala module
+ SCALA = getModule(Names.scala);
+ // the scala class
+ SCALA_CLASS = SCALA.moduleClass();
+ // the scala package as a prefix
+ SCALA_TYPE = Type.singleType(ROOT_TYPE, SCALA);
+
+ // the java module
+ JAVA = getModule(Names.java);
+ // the java class
+ JAVA_CLASS = JAVA.moduleClass();
+ // the java package as a prefix
+ JAVA_TYPE = Type.singleType(ROOT_TYPE, JAVA);
+
+ // the java.lang module
+ JAVALANG = getModule(Names.java_lang);
+ // the java.lang class
+ JAVALANG_CLASS = JAVALANG.moduleClass();
+ // the java.lang package as a prefix
+ JAVALANG_TYPE = Type.singleType(JAVA_TYPE, JAVALANG);
+
+ // the scala.runtime module
+ SCALARUNTIME = getModule(Names.scala_runtime);
+ // the scala.runtime class
+ SCALARUNTIME_CLASS = SCALARUNTIME.moduleClass();
+ // the scala.runtime package as a prefix
+ SCALARUNTIME_TYPE = Type.singleType(SCALA_TYPE, SCALARUNTIME);
+
+ // the scala.ANY classs
+ ANY_CLASS = new ClassSymbol(
+ Position.NOPOS, Names.Any.toTypeName(), SCALA_CLASS, Modifiers.JAVA);
+ SCALA_CLASS.members().enter(ANY_CLASS);
+ ANY_TYPE = monoType(ANY_CLASS);
+ ANY_CLASS.setInfo(Type.compoundType(Type.EMPTY_ARRAY, new Scope(), ANY_CLASS));
+ ANY_CLASS.constructor().setInfo(
+ Type.PolyType(Symbol.EMPTY_ARRAY, ANY_TYPE));
+
+ // the java.lang.OBJECT class
+ JAVA_OBJECT_CLASS = getClass(Names.java_lang_Object);
+ JAVA_OBJECT_TYPE = monoType(JAVA_OBJECT_CLASS);
+ JAVA_OBJECT_CLASS.setInfo(pparser.classCompletion);
+
+ // the scala.ANYREF class
+ ANYREF_CLASS = new TypeSymbol(
+ Kinds.ALIAS, Position.NOPOS, Names.AnyRef.toTypeName(),
+ SCALA_CLASS, Modifiers.JAVA)
+ .setInfo(JAVA_OBJECT_TYPE);
+ ANYREF_CLASS.constructor().setInfo(
+ Type.PolyType(Symbol.EMPTY_ARRAY, Type.NoType));
+
+ ANYREF_TYPE = monoType(ANYREF_CLASS);
+ SCALA.members().enter(ANYREF_CLASS);
+
+ // the scala.OBJECT class
+ OBJECT_CLASS = getClass(Names.scala_Object);
+ OBJECT_TYPE = monoType(OBJECT_CLASS);
+
+ // the scala.ANYVAL class
+ ANYVAL_CLASS = getClass(Names.scala_AnyVal);
+ ANYVAL_TYPE = monoType(ANYVAL_CLASS);
+
+ // the primitive types
+ DOUBLE_CLASS = getClass(Names.scala_Double);
+ DOUBLE_TYPE = monoType(DOUBLE_CLASS);
+ FLOAT_CLASS = getClass(Names.scala_Float);
+ FLOAT_TYPE = monoType(FLOAT_CLASS);
+ LONG_CLASS = getClass(Names.scala_Long);
+ LONG_TYPE = monoType(LONG_CLASS);
+ INT_CLASS = getClass(Names.scala_Int);
+ INT_TYPE = monoType(INT_CLASS);
+ CHAR_CLASS = getClass(Names.scala_Char);
+ CHAR_TYPE = monoType(CHAR_CLASS);
+ SHORT_CLASS = getClass(Names.scala_Short);
+ SHORT_TYPE = monoType(SHORT_CLASS);
+ BYTE_CLASS = getClass(Names.scala_Byte);
+ BYTE_TYPE = monoType(BYTE_CLASS);
+ BOOLEAN_CLASS = getClass(Names.scala_Boolean);
+ BOOLEAN_TYPE = monoType(BOOLEAN_CLASS);
+ UNIT_CLASS = getClass(Names.scala_Unit);
+ UNIT_TYPE = monoType(UNIT_CLASS);
+
+ // the array class
+ ARRAY_CLASS = getClass(Names.scala_Array);
+
+ // add members to java.lang.Throwable
+ JAVA_THROWABLE_CLASS = getClass(Names.java_lang_Throwable);
+ JAVA_THROWABLE_TYPE = monoType(JAVA_THROWABLE_CLASS);
+ THROW = new TermSymbol(
+ Position.NOPOS, Names.throw_, JAVA_THROWABLE_CLASS, Modifiers.FINAL);
+ Symbol tvar = newTypeParameter(THROW, ANY_TYPE);
+ THROW.setInfo(Type.PolyType(new Symbol[]{tvar}, tvar.type()));
+ JAVA_THROWABLE_CLASS.members().enter(THROW);
+
+ // add the java.lang.String class to the scala package
+ JAVA_STRING_CLASS = getClass(Names.java_lang_String);
+ JAVA_STRING_TYPE = monoType(JAVA_STRING_CLASS);
+ STRING_CLASS = new TypeSymbol(
+ Kinds.ALIAS, Position.NOPOS, Names.String.toTypeName(), SCALA_CLASS, 0)
+ .setInfo(JAVA_STRING_TYPE);
+ STRING_CLASS.constructor().setInfo(
+ Type.PolyType(Symbol.EMPTY_ARRAY, Type.NoType));
+ STRING_TYPE = monoType(STRING_CLASS);
+ SCALA.members().enter(STRING_CLASS);
+
+ /*
+ ANY_PLUS_STRING = new TermSymbol(
+ Position.NOPOS, Names.PLUS, ANY_CLASS, Modifiers.FINAL);
+ ANY_PLUS_STRING.setInfo(
+ Type.MethodType(
+ new Symbol[]{newParameter(ANY_PLUS_STRING, STRING_TYPE)},
+ STRING_TYPE));
+ ANY_CLASS.members().enter(ANY_PLUS_STRING);
+ */
+
+ STRING_PLUS_ANY = new TermSymbol(
+ Position.NOPOS, Names.PLUS, STRING_CLASS, Modifiers.FINAL);
+ STRING_PLUS_ANY.setInfo(
+ Type.MethodType(
+ new Symbol[]{newParameter(STRING_PLUS_ANY, ANY_TYPE)},
+ STRING_TYPE));
+ STRING_CLASS.members().enter(STRING_PLUS_ANY);
+
+ // add members to class scala.Any
+ MATCH = new TermSymbol(
+ Position.NOPOS, Names.match, ANY_CLASS, Modifiers.FINAL);
+ MATCH.setInfo(
+ Type.MethodType(
+ new Symbol[]{newParameter(MATCH, OBJECT_TYPE)},
+ OBJECT_TYPE));
+ ANY_CLASS.members().enter(MATCH);
+
+ AS = new TermSymbol(
+ Position.NOPOS, Names.as, ANY_CLASS, Modifiers.FINAL);
+ tvar = newTypeParameter(AS, ANY_TYPE);
+ AS.setInfo(Type.PolyType(new Symbol[]{tvar}, tvar.type()));
+ ANY_CLASS.members().enter(AS);
+
+ IS = new TermSymbol(
+ Position.NOPOS, Names.is, ANY_CLASS, Modifiers.FINAL);
+ IS.setInfo(Type.PolyType(new Symbol[]{newTypeParameter(IS, ANY_TYPE)},
+ BOOLEAN_TYPE));
+ ANY_CLASS.members().enter(IS);
+
+ EQEQ = new TermSymbol(
+ Position.NOPOS, Names.EQEQ, ANY_CLASS, 0);
+ EQEQ.setInfo(Type.MethodType(new Symbol[]{newParameter(EQEQ, ANY_TYPE)},
+ BOOLEAN_TYPE));
+ ANY_CLASS.members().enter(EQEQ);
+
+ BANGEQ = new TermSymbol(
+ Position.NOPOS, Names.BANGEQ, ANY_CLASS, 0);
+ BANGEQ.setInfo(Type.MethodType(new Symbol[]{newParameter(BANGEQ, ANY_TYPE)},
+ BOOLEAN_TYPE));
+ ANY_CLASS.members().enter(BANGEQ);
+
+ TOSTRING = new TermSymbol(
+ Position.NOPOS, Names.toString, ANY_CLASS, 0);
+ TOSTRING.setInfo(Type.MethodType(Symbol.EMPTY_ARRAY, STRING_TYPE));
+ ANY_CLASS.members().enter(TOSTRING);
+
+ HASHCODE = new TermSymbol(
+ Position.NOPOS, Names.hashCode, ANY_CLASS, 0);
+ HASHCODE.setInfo(Type.MethodType(Symbol.EMPTY_ARRAY, INT_TYPE));
+ ANY_CLASS.members().enter(HASHCODE);
+
+ // add a null value to the root scope
+ NULL = new TermSymbol(
+ Position.NOPOS, Names.null_, ROOT_CLASS, 0);
+ tvar = newTypeParameter(NULL, ANYREF_TYPE);
+ NULL.setInfo(Type.PolyType(new Symbol[]{tvar}, tvar.type()));
+ ROOT.members().enter(NULL);
+ }
+
+ private Symbol newParameter(Symbol owner, Type tp) {
+ return new TermSymbol(Position.NOPOS, Name.fromString("v"), owner, Modifiers.PARAM)
+ .setInfo(tp);
+ }
+
+ private Symbol newTypeParameter(Symbol owner, Type bound) {
+ return new TypeSymbol(
+ Kinds.TYPE, Position.NOPOS, Name.fromString("T").toTypeName(), owner, Modifiers.PARAM)
+ .setInfo(bound);
+ }
+
+ public Symbol getModule(Name fullname) {
+ Scope scope = ROOT_CLASS.members();
+ int i = 0;
+ int j = fullname.pos((byte)'.', i);
+ while (j < fullname.length()) {
+ scope = scope.lookup(fullname.subName(i, j)).members();
+ i = j + 1;
+ j = fullname.pos((byte)'.', i);
+ }
+ Symbol sym = scope.lookup(fullname.subName(i, fullname.length()));
+ if (!sym.isModule()) {
+ switch (sym.type()) {
+ case OverloadedType(Symbol[] alts, Type[] alttypes):
+ for (int k = 0; k < alts.length; k++)
+ if ((sym = alts[k]).isModule()) break;
+ }
+ }
+ assert sym.isModule() : "no module '" + fullname + "'";
+ return sym;
+ }
+
+ public Symbol getClass(Name fullname) {
+ Scope scope = ROOT_CLASS.members();
+ int i = 0;
+ int j = fullname.pos((byte)'.', i);
+ while (j < fullname.length()) {
+ scope = scope.lookup(fullname.subName(i, j)).members();
+ i = j + 1;
+ j = fullname.pos((byte)'.', i);
+ }
+ Symbol sym = scope.lookup(fullname.subName(i, fullname.length()).toTypeName());
+ assert sym.kind != Kinds.NONE : "no class '" + fullname + "'";
+ return sym;
+ }
+
+ public Type getType(Name fullname) {
+ return getClass(fullname).type();
+ }
+
+ public Type monoType(Symbol c) {
+ return Type.TypeRef(c.owner().thisType(), c, Type.EMPTY_ARRAY);
+ }
+
+ public Type getJavaType(Name fullname) {
+ return monoType(getClass(fullname));
+ }
+
+ private void loadBooleanMembers() {
+ if (TRUE != null) return;
+ Symbol booleanStatics = getModule(Names.scala_Boolean);
+ TRUE = booleanStatics.members().lookup(Names.True);
+ FALSE = booleanStatics.members().lookup(Names.False);
+ BARBAR = BOOLEAN_TYPE.lookup(Names.BARBAR);
+ AMPAMP = BOOLEAN_TYPE.lookup(Names.AMPAMP);
+ }
+
+ public Type arrayType(Type elemtpe) {
+ return Type.appliedType(monoType(ARRAY_CLASS), new Type[]{elemtpe});
+ }
+
+ public Type functionType(Type[] argtps, Type restp) {
+ Type[] argtps1 = new Type[argtps.length + 1];
+ System.arraycopy(argtps, 0, argtps1, 0, argtps.length);
+ argtps1[argtps.length] = Type.covarType(restp);
+ return Type.appliedType(
+ getType(Name.fromString("scala.Function" + argtps.length)),
+ argtps1);
+ }
+
+ public Type tupleType(Type[] args) {
+ assert args.length > 0;
+ Type[] args1 = new Type[args.length];
+ for (int i = 0; i < args.length; i++)
+ args1[i] = Type.covarType(args[i]);
+ return Type.appliedType(
+ getType(Name.fromString("scala.Tuple" + args.length)), args1);
+ }
+}
diff --git a/sources/scalac/symtab/Kinds.java b/sources/scalac/symtab/Kinds.java
new file mode 100644
index 0000000000..8902ff4699
--- /dev/null
+++ b/sources/scalac/symtab/Kinds.java
@@ -0,0 +1,28 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab;
+
+
+public interface Kinds {
+
+ /** kind of error symbol
+ */
+ int ERROR = 0;
+
+ /** kind of non-existent symbol
+ */
+ int NONE = 1;
+
+ /** definition kinds
+ */
+ int ALIAS = 2;
+ int CLASS = 3;
+ int TYPE = 4;
+ int VAL = 5;
+}
diff --git a/sources/scalac/symtab/Modifiers.java b/sources/scalac/symtab/Modifiers.java
new file mode 100644
index 0000000000..3fc119419e
--- /dev/null
+++ b/sources/scalac/symtab/Modifiers.java
@@ -0,0 +1,135 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab;
+
+public interface Modifiers {
+
+ // modifiers
+ int ABSTRACT = 0x00000001;
+ int FINAL = 0x00000002;
+ int PRIVATE = 0x00000004;
+ int PROTECTED = 0x00000008;
+
+ int QUALIFIED = 0x00000010;
+ int OVERRIDE = 0x00000020;
+ int CASE = 0x00000040;
+ int ABSTRACTCLASS = 0x00000080; // abstract class
+
+ int DEF = 0x00000100; // a def parameter
+ int SYNTHETIC = 0x00000200;
+ int DEPRECATED = 0x00000400;
+ int JAVA = 0x00000800; // symbol was defined by a Java class
+
+ int MODUL = 0x00001000; // symbol is module or class implementing a module
+ int MUTABLE = 0x00002000; // symbol is a mutable variable.
+ int PARAM = 0x00004000; // symbol is a (type) parameter to a method
+
+ int INITIALIZED = 0x00010000; // symbol's definition is complete
+ int LOCKED = 0x00020000; // temporary flag to catch cyclic dependencies
+ int ACCESSED = 0x00040000; // symbol was accessed at least once
+ int SELECTOR = 0x00080000; // symbol was used as selector in Select
+
+ int PACKAGE = 0x00100000; // symbol is a java packages.
+ int LABEL = 0x00200000; // symbol is a label symbol
+ int STATIC = 0x00400000; // "static" inner classes (i.e. after class norm.)
+ int STABLE = 0x00800000; // functions that are assumed to be stable
+ // (typically, access methods for valdefs)
+
+ int CAPTURED = 0x01000000; // variables is accessed from nested function.
+
+ int ACCESSOR = 0x04000000; // function is an access function for a
+ // value or variable
+ int BRIDGE = 0x0800000; // function is a bridge method.
+
+ int INTERFACE = 0x10000000; // symbol is a Java interface
+ int TRAIT = 0x20000000; // symbol is a Trait
+
+ int SNDTIME = 0x40000000; //debug
+
+ // masks
+ int SOURCEFLAGS = 0x00000077 | PARAM | TRAIT; // these modifiers can be set in source programs.
+ int ACCESSFLAGS = PRIVATE | PROTECTED;
+
+ public static class Helper {
+
+ public static boolean isAbstract(int flags) {
+ return (flags & (ABSTRACT | ABSTRACTCLASS)) != 0;
+ }
+
+ public static boolean isFinal(int flags) {
+ return (flags & FINAL) != 0;
+ }
+
+ public static boolean isPrivate(int flags) {
+ return (flags & PRIVATE) != 0;
+ }
+
+ public static boolean isProtected(int flags) {
+ return (flags & PROTECTED) != 0;
+ }
+
+ public static boolean isQualified(int flags) {
+ return (flags & QUALIFIED) != 0;
+ }
+
+ public static boolean isOverride(int flags) {
+ return (flags & OVERRIDE) != 0;
+ }
+
+ public static boolean isCase(int flags) {
+ return (flags & CASE) != 0;
+ }
+
+ public static boolean isInterface(int flags) {
+ return (flags & INTERFACE) != 0;
+ }
+
+ public static boolean isDef(int flags) {
+ return (flags & DEF) != 0;
+ }
+
+ public static boolean isModClass(int flags) {
+ return (flags & MODUL) != 0;
+ }
+
+ public static boolean isStatic(int flags) {
+ return (flags & STATIC) != 0;
+ }
+
+ public static boolean isJava(int flags) {
+ return (flags & JAVA) != 0;
+ }
+
+ public static boolean isNoVal(int flags) {
+ return (flags & PACKAGE) != 0;
+ }
+
+ public static String toString(int flags) {
+ StringBuffer buffer = new StringBuffer();
+ toString(buffer, flags);
+ return buffer.toString();
+ }
+
+ public static void toString(StringBuffer buffer, int flags) {
+ //buffer.append(flags).append(": ");//debug
+ int marker = buffer.length();
+ if (isPrivate(flags)) buffer.append("private ");
+ if (isProtected(flags)) buffer.append("protected ");
+ if (isAbstract(flags)) buffer.append("abstract ");
+ if (isFinal(flags)) buffer.append("final ");
+ if (isQualified(flags)) buffer.append("qualified ");
+ if (isInterface(flags)) buffer.append("interface ");
+ if (isCase(flags)) buffer.append("case ");
+ if (isDef(flags)) buffer.append("def ");
+ if (isOverride(flags)) buffer.append("override ");
+ int length = buffer.length();
+ buffer.setLength(length - (length == marker ? 0 : 1));
+ }
+ }
+}
diff --git a/sources/scalac/symtab/NameMangler.java b/sources/scalac/symtab/NameMangler.java
new file mode 100644
index 0000000000..30de8193d0
--- /dev/null
+++ b/sources/scalac/symtab/NameMangler.java
@@ -0,0 +1,33 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+**
+** $Id$
+\* */
+
+package scalac.symtab;
+
+import scalac.util.Name;
+import java.util.HashMap;
+
+public class NameMangler {
+
+ private HashMap/*<Symbol,HashMap<Symbol,int[]>>*/ mangleMap = new HashMap();
+
+ public void setMangledName(Symbol innerclazz) {
+ Symbol topclazz = innerclazz.enclToplevelClass();
+ HashMap map = (HashMap) mangleMap.get(topclazz);
+ if (map == null) {
+ map = new HashMap();
+ mangleMap.put(topclazz, map);
+ }
+ int[] ctr = (int[]) map.get(innerclazz);
+ if (ctr == null) {
+ ctr = new int[1];
+ map.put(innerclazz, ctr);
+ }
+ innerclazz.setMangledName(
+ Name.fromString(topclazz.name + "$" + (ctr[0]++) + innerclazz.name));
+ }
+}
diff --git a/sources/scalac/symtab/Scope.java b/sources/scalac/symtab/Scope.java
new file mode 100644
index 0000000000..3bd22f51ed
--- /dev/null
+++ b/sources/scalac/symtab/Scope.java
@@ -0,0 +1,306 @@
+ /* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab;
+
+import scalac.util.*;
+import scalac.ApplicationError;
+
+public class Scope {
+
+ public static abstract class SymbolIterator {
+ public abstract boolean hasNext();
+ public abstract Symbol next();
+ }
+
+ /** A symbol iterator that returns all alternatives of an overloaded symbol
+ * instead of the overloaded symbol itself.
+ */
+ public static class UnloadIterator extends SymbolIterator {
+ private SymbolIterator iterator;
+ private Symbol[] alternatives;
+ private int index;
+
+ public UnloadIterator(SymbolIterator iterator) {
+ this.iterator = iterator;
+ this.alternatives = null;
+ this.index = -1;
+ }
+
+ public boolean hasNext() {
+ return index >= 0 || iterator.hasNext();
+ }
+ public Symbol next() {
+ if (index >= 0) {
+ Symbol symbol = alternatives[index++];
+ if (index == alternatives.length) {
+ alternatives = null;
+ index = -1;
+ }
+ return symbol;
+ } else {
+ Symbol symbol = iterator.next();
+ switch (symbol.type()) {
+ case OverloadedType(Symbol[] alts, _):
+ alternatives = alts;
+ index = 0;
+ return next();
+ default:
+ return symbol;
+ }
+ }
+ }
+ }
+
+ public static class Entry {
+
+ /** the absent entry
+ */
+ public static final Entry NONE = new Entry();
+
+ /** the symbol of the entry (this is the symbol containing the name)
+ */
+ public Symbol sym;
+
+ /** the next entry in the hash bucket
+ */
+ Entry tail;
+
+ /** the next entry in this scope
+ */
+ public Entry next;
+
+ /** The owner of the entry;
+ */
+ public Scope owner;
+
+ Entry(Symbol sym, Scope owner) {
+ if (sym == null) throw new ApplicationError();
+ this.sym = sym;
+ this.owner = owner;
+ this.next = owner.elems;
+ owner.elems = this;
+ }
+
+ private Entry() {
+ this.sym = Symbol.NONE;
+ }
+
+ public Entry setSymbol(Symbol sym) {
+ this.sym = sym;
+ owner.elemsCache = null;
+ return this;
+ }
+
+ public int hashCode() {
+ return sym.name.index;
+ }
+
+ public String toString() {
+ return sym.toString();
+ }
+ }
+
+ /** all elements of this scope
+ */
+ public Entry elems;
+
+ /** the hash table
+ */
+ private Entry[] hashtable;
+
+ /** a cache for all elements, to be used by symbol iterator.
+ */
+ private Symbol[] elemsCache = null;
+
+ /** size and mask of hash tables
+ * todo: make hashtables grow?
+ */
+ private final int HASHSIZE = 0x80;
+ private final int HASHMASK = 0x7f;
+
+ /** the threshold number of entries from which a hashtable is constructed.
+ */
+ private final int MIN_HASH = 6;
+
+ /** construct a new name space
+ */
+ public Scope() {
+ this.elems = Entry.NONE;
+ }
+
+ public Scope(Entry elems) {
+ this.elems = elems;
+ if (size() >= MIN_HASH) createHash();
+ }
+
+ public Scope(Scope base) {
+ this.elems = base.elems;
+ if (base.hashtable != null) {
+ this.hashtable = new Entry[HASHSIZE];
+ for (int i = 0; i < HASHSIZE; i++)
+ hashtable[i] = base.hashtable[i];
+ }
+ }
+
+ public Scope(Symbol[] members) {
+ this();
+ for (int i = 0; i < members.length; i++)
+ enter(members[i]);
+ }
+
+ /** the number of entries in this scope
+ */
+ int size() {
+ int s = 0;
+ for (Entry e = elems; e != Entry.NONE; e = e.next) s++;
+ return s;
+ }
+
+ private Scope enter(Entry e) {
+ elems = e;
+ elemsCache = null;
+ if (hashtable != null) {
+ int i = e.sym.name.index & HASHMASK;
+ elems.tail = hashtable[i];
+ hashtable[i] = elems;
+ } else if (size() >= MIN_HASH) {
+ createHash();
+ }
+ return this;
+ }
+
+ /** enter a symbol
+ */
+ public Scope enter(Symbol sym) {
+ return enter(new Entry(sym, this));
+ }
+
+ public Scope enterOrOverload(Symbol sym) {
+ Entry e = lookupEntry(sym.name);
+ if (e.owner == this && (sym.flags & Modifiers.PRIVATE) == 0) {
+ e.setSymbol(e.sym.overloadWith(sym));
+ return this;
+ } else {
+ return enter(sym);
+ }
+ }
+
+ private void createHash() {
+ hashtable = new Entry[HASHSIZE];
+ for (int i = 0; i < HASHSIZE; i++)
+ hashtable[i] = Entry.NONE;
+ enterInHash(elems);
+ }
+
+ private void enterInHash(Entry e) {
+ if (e != Entry.NONE) {
+ enterInHash(e.next);
+ int i = e.sym.name.index & HASHMASK;
+ e.tail = hashtable[i];
+ hashtable[i] = e;
+ }
+ }
+
+ /** remove entry
+ */
+ public void unlink(Entry e) {
+ Entry e1 = hashtable[e.sym.name.index & HASHMASK];
+ if (e1 == e) {
+ hashtable[e.sym.name.index & HASHMASK] = e.tail;
+ } else {
+ while (e1.tail != e) e1 = e1.tail;
+ }
+ if (elems == e) {
+ elems = e.next;
+ } else {
+ e1 = elems;
+ while (e1.next != e) e1 = e1.next;
+ e1.next = e.next;
+ }
+ elemsCache = null;
+ }
+
+ /** lookup a symbol
+ */
+ public Symbol lookup(Name name) {
+ return lookupEntry(name).sym;
+ }
+
+ /** lookup a symbol entry.
+ */
+ public Entry lookupEntry(Name name) {
+ Entry e;
+ if (hashtable != null) {
+ e = hashtable[name.index & HASHMASK];
+ while (e != Entry.NONE && e.sym.name != name) e = e.tail;
+ } else {
+ e = elems;
+ while (e != Entry.NONE && e.sym.name != name) e = e.next;
+ }
+ return e;
+ }
+
+ /** return all symbols as an array,
+ * in the order they were entered in this scope.
+ */
+ public Symbol[] elements() {
+ if (elemsCache == null) {
+ int s = size();
+ elemsCache = new Symbol[s];
+ for (Entry e = elems; e != Entry.NONE; e = e.next)
+ elemsCache[--s] = e.sym;
+ }
+ return elemsCache;
+ }
+
+ /** return all symbols as an iterator,
+ * in the order they were entered in this scope.
+ */
+ public SymbolIterator iterator() { return new MySymbols(); }
+
+ class MySymbols extends SymbolIterator {
+
+ private int index;
+ MySymbols() {
+ elements();
+ index = 0;
+ }
+
+ public boolean hasNext() {
+ return index < elemsCache.length;
+ }
+
+ public Symbol next() {
+ return elemsCache[index++];
+ }
+ }
+
+ public String toString() {
+ StringBuffer str = new StringBuffer("{");
+ SymbolIterator it = iterator();
+ while (it.hasNext()) {
+ str.append("\n " + it.next().defString());
+ }
+ str.append("}");
+ return str.toString();
+ }
+
+ public String simpleToString() {
+ StringBuffer str = new StringBuffer("{");
+ SymbolIterator it = iterator();
+ while (it.hasNext()) {
+ str.append("\n " + it.next().name);
+ }
+ str.append("}");
+ return str.toString();
+ }
+
+ public static Scope EMPTY = new Scope();
+}
+
diff --git a/sources/scalac/symtab/SourceCompleter.java b/sources/scalac/symtab/SourceCompleter.java
new file mode 100644
index 0000000000..1656f2029f
--- /dev/null
+++ b/sources/scalac/symtab/SourceCompleter.java
@@ -0,0 +1,53 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab;
+
+import scalac.*;
+import scalac.ast.parser.*;
+import scalac.typechecker.Analyzer;
+import java.io.*;
+
+
+public class SourceCompleter extends Type.LazyType {
+
+ /** the global compilation environment
+ */
+ protected Global global;
+ protected String filename;
+ private boolean completed = false;
+
+ public SourceCompleter(Global global, String filename) {
+ this.global = global;
+ this.filename = filename;
+ }
+
+ /** complete class symbol c by loading the class
+ */
+ public void complete(Symbol c) {
+ if (completed) {
+ c.setInfo(Type.ErrorType);
+ } else if (filename != null) {
+ try {
+ String fname = filename;
+ long msec = System.currentTimeMillis();
+ Unit unit = new Unit(global, new Sourcefile(filename, false));
+ filename = null;
+ global.PHASE.PARSER.createPhase(global).apply(unit);
+ ((Analyzer)global.PHASE.ANALYZER.createPhase(global)).lateEnter(unit, c);
+ global.operation("added " + fname + " in " +
+ (System.currentTimeMillis() - msec) + "ms");
+ } catch (IOException e) {
+ e.printStackTrace();
+ global.error("i/o error while loading " + c);
+ c.setInfo(Type.ErrorType);
+ }
+ completed = true;
+ }
+ }
+}
diff --git a/sources/scalac/symtab/SymSet.java b/sources/scalac/symtab/SymSet.java
new file mode 100644
index 0000000000..f72b9764f5
--- /dev/null
+++ b/sources/scalac/symtab/SymSet.java
@@ -0,0 +1,89 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id$
+
+package scalac.symtab;
+
+/** Sets of symbols, implemented as binary trees.
+ */
+public class SymSet {
+ private SymSet l, r;
+ private Symbol sym;
+
+ public SymSet() {}
+
+ private SymSet(Symbol sym, SymSet l, SymSet r) {
+ this.sym = sym; this.l = l; this.r = r;
+ }
+
+ /** Union of this set and `{sym}'.
+ */
+ public SymSet incl(Symbol sym) {
+ if (this == EMPTY) {
+ return new SymSet(sym, EMPTY, EMPTY);
+ } else if (sym == this.sym) {
+ return this;
+ } else if (sym.isLess(this.sym)) {
+ return new SymSet(this.sym, l.incl(sym), r);
+ } else {
+ assert this.sym.isLess(sym);
+ return new SymSet(this.sym, l, r.incl(sym));
+ }
+ }
+
+ /** Is `sym' an element of this set?
+ */
+ public boolean contains(Symbol sym) {
+ if (this == EMPTY) {
+ return false;
+ } else if (sym == this.sym) {
+ return true;
+ } else if (sym.isLess(this.sym)) {
+ return l.contains(sym);
+ } else {
+ assert this.sym.isLess(sym);
+ return r.contains(sym);
+ }
+ }
+
+ /** The number of elements in ths set.
+ */
+ public int size() {
+ if (this == EMPTY) {
+ return 0;
+ } else {
+ return 1 + l.size() + r.size();
+ }
+ }
+
+ /** Copy elements of this set into `ss', starting at index `from'.
+ * Return index one past last element copied.
+ */
+ public int copyToArray(Symbol[] ss, int from) {
+ if (this == EMPTY) {
+ return from;
+ } else {
+ from = l.copyToArray(ss, from);
+ ss[from] = sym;
+ return r.copyToArray(ss, from + 1);
+ }
+ }
+
+ /** Return all elements of this set as an array.
+ */
+ public Symbol[] toArray() {
+ int s = size();
+ if (s == 0) return Symbol.EMPTY_ARRAY;
+ Symbol[] ss = new Symbol[s];
+ copyToArray(ss, 0);
+ return ss;
+ }
+
+ /** The empty set.
+ */
+ public final static SymSet EMPTY = new SymSet();
+}
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;
+ }
+}
+
diff --git a/sources/scalac/symtab/Type.java b/sources/scalac/symtab/Type.java
new file mode 100644
index 0000000000..3ec37799f4
--- /dev/null
+++ b/sources/scalac/symtab/Type.java
@@ -0,0 +1,2353 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+**
+** $Id$
+\* */
+//todo: implement rule single
+
+package scalac.symtab;
+
+import scalac.ApplicationError;
+import scalac.util.*;
+import scalac.Global;
+
+public class Type implements Modifiers, Kinds, TypeTags {
+
+ public static boolean debugSwitch = false;
+ private static int indent = 0;
+
+ //todo: convert C with {} to C.
+
+ public case ErrorType; // not used after analysis
+ public case AnyType; // not used after analysis
+ public case NoType;
+
+ public case ThisType(Symbol sym);
+
+ public case TypeRef(Type pre, Symbol sym, Type[] args);
+
+ public case SingleType(Type pre, Symbol sym) {
+ assert this instanceof ExtSingleType;
+ }
+
+ public case CompoundType(Type[] parts, Scope members) {
+ assert this instanceof ExtCompoundType;
+ }
+ public case MethodType(Symbol[] vparams, Type result);
+ public case PolyType(Symbol[] tparams, Type result);
+ public case OverloadedType(Symbol[] alts, Type[] alttypes);
+
+ /** Type such as +T. Only used as type arguments.
+ */
+ public case CovarType(Type tp) {
+ assert !(tp instanceof CovarType);
+ }
+
+ /** Hidden case to implement delayed evaluation of types.
+ * No need to pattern match on this type; it will never come up.
+ */
+ public case LazyType();
+
+ /** Hidden case to implement local type inference.
+ * Later phases do not need to match on this type.
+ */
+ public case TypeVar(Type origin, Constraint constr);
+
+ /** Hidden cases to implement type erasure.
+ * Earlier phases do not need to match on these types.
+ */
+ public case UnboxedType(int tag);
+ public case UnboxedArrayType(Type elemtp);
+
+ /** Force evaluation of a lazy type. No cycle
+ * check is needed; since this is done in Symbol.
+ * @see Symbol.info().
+ */
+ public void complete(Symbol p) {}
+
+// Creators ---------------------------------------------------------------------
+
+ /** An owner-less ThisType
+ */
+ public static Type localThisType = ThisType(Symbol.NONE);
+
+ /** An empty Type array */
+ public static final Type[] EMPTY_ARRAY = new Type[0];
+
+ /** A non-existing Type array; used to express type erasure */
+ public static final Type[] NO_ARRAY = new Type[0];
+
+ public static SingleType singleType(Type pre, Symbol sym) {
+ return new ExtSingleType(pre, sym);
+ }
+
+ public static TypeRef appliedType(Type tycon, Type[] args) {
+ switch (tycon) {
+ case TypeRef(Type pre, Symbol sym, Type[] args1):
+ if (args == args1) return (TypeRef)tycon;
+ else return TypeRef(pre, sym, args);
+ default:
+ throw new ApplicationError();
+ }
+ }
+
+ public static CovarType covarType(Type tp) {
+ if (tp instanceof CovarType) return (CovarType)tp;
+ else return CovarType(tp);
+ }
+
+ public static CompoundType compoundType(Type[] parts, Scope members,
+ Symbol clazz) {
+ ExtCompoundType res = new ExtCompoundType(parts, members);
+ res.tsym = clazz;
+ return res;
+ }
+
+ public static CompoundType compoundType(Type[] parts, Scope members) {
+ ExtCompoundType res = new ExtCompoundType(parts, members);
+ res.tsym = new ClassSymbol(
+ Position.NOPOS, Names.COMPOUND_NAME.toTypeName(), Symbol.NONE,
+ SYNTHETIC | ABSTRACTCLASS);
+ res.tsym.setInfo(res);
+ res.tsym.constructor().setInfo(
+ Type.PolyType(Symbol.EMPTY_ARRAY, Type.NoType));
+ return res;
+ }
+
+ static class ExtSingleType extends SingleType {
+ Type tp = null;
+ int definedId = -1;
+ ExtSingleType(Type pre, Symbol sym) {
+ super(pre, sym);
+ }
+ public Type widen() {
+ if (definedId != Global.instance.currentPhase.id) {
+ definedId = Global.instance.currentPhase.id;
+ tp = pre.memberType(sym).widen();
+ }
+ return tp;
+ }
+ }
+
+ static class ExtCompoundType extends CompoundType {
+ Symbol tsym;
+ ExtCompoundType(Type[] parts, Scope members) {
+ super(parts, members);
+ }
+ public Symbol symbol() {
+ return tsym;
+ }
+ void validate() {//debug
+ for (Scope.Entry e = members.elems; e != Scope.Entry.NONE; e = e.next)
+ assert e.sym.owner() == tsym;
+ }
+ }
+
+ void validate() {//debug
+ }
+
+// Access methods ---------------------------------------------------------------
+
+ /** If this is a thistype, named type, applied type, singleton type, or compound type,
+ * its symbol, otherwise Symbol.NONE.
+ */
+ public Symbol symbol() {
+ switch (this) {
+ case ErrorType:
+ return Symbol.ERROR;
+ case ThisType(Symbol sym):
+ return sym;
+ case TypeRef(_, Symbol sym, _):
+ return sym;
+ case SingleType(_, Symbol sym):
+ return sym;
+ case TypeVar(Type origin, _):
+ return origin.symbol();
+ case CompoundType(_, _):
+ // overridden in ExtCompoundType
+ throw new ApplicationError();
+ default:
+ return Symbol.NONE;
+ }
+ }
+
+ public static Symbol[] symbol(Type[] tps) {
+ Symbol[] syms = new Symbol[tps.length];
+ for (int i = 0; i < syms.length; i++)
+ syms[i] = tps[i].symbol();
+ return syms;
+ }
+
+ /** If this type is a thistype or singleton type, its underlying object type,
+ * otherwise the type itself.
+ */
+ public Type widen() {
+ switch (this) {
+ case ThisType(Symbol sym):
+ return sym.type();
+ case SingleType(Type pre, Symbol sym):
+ // overridden in ExtSingleType
+ throw new ApplicationError();
+ case TypeVar(Type origin, Constraint constr):
+ if (constr.inst != NoType) return constr.inst.widen();
+ else return this;
+ default:
+ return this;
+ }
+ }
+
+ public static Type[] widen(Type[] tps) {
+ if (tps.length == 0) return Type.EMPTY_ARRAY;
+ Type[] tps1 = new Type[tps.length];
+ for (int i = 0; i < tps1.length; i++) {
+ tps1[i] = tps[i].widen();
+ assert !(tps1[i] instanceof SingleType) : tps[i];//debug
+ }
+ return tps1;
+ }
+
+ /** The thistype or singleton type corresponding to values of this type.
+ */
+ public Type narrow() {
+ switch (this) {
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ if (sym.kind == ALIAS) return pre.memberInfo(sym).narrow();
+ else if (sym.kind == CLASS) return sym.thisType();
+ else return ThisType(sym);
+ case CompoundType(_, _):
+ return symbol().thisType();
+ default:
+ return this;
+ }
+ }
+
+ /** The this is a this-type, named-type, applied type or single-type, its prefix,
+ * otherwise NoType.
+ */
+ public Type prefix() {
+ switch (this) {
+ case ThisType(Symbol sym): return sym.owner().thisType();
+ case TypeRef(Type pre, _, _): return pre;
+ case SingleType(Type pre, _): return pre;
+ case TypeVar(Type origin, Constraint constr):
+ if (constr.inst != NoType) return constr.inst.prefix();
+ else return NoType;
+ default: return NoType;
+ }
+ }
+
+ /** Get all type arguments of this type.
+ */
+ public Type[] typeArgs() {
+ switch (unalias()) {
+ case TypeRef(_, _, Type[] args):
+ return args;
+ default:
+ return Type.EMPTY_ARRAY;
+ }
+ }
+
+ /** Remove all aliases
+ */
+ public Type unalias() {
+ Type result = unalias(0);//debug
+ //if (this != result) System.out.println(this + " ==> " + result);//DEBUG
+ return result;
+ }
+
+ private Type unalias(int n) {
+ if (n == 20) throw new Type.Error("recursive type alias: " + this);
+ switch (this) {
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ if (sym.kind == ALIAS) {
+ return pre.memberInfo(sym).subst(sym.typeParams(), args).unalias(n + 1);
+ }
+ break;
+ case TypeVar(Type origin, Constraint constr):
+ if (constr.inst != NoType) return constr.inst.unalias(n + 1);
+ else return this;
+ }
+ return this;
+ }
+
+ /** The (prefix-adapted) parents of this type.
+ */
+ public Type[] parents() {
+ switch (unalias()) {
+ case ThisType(_):
+ case SingleType(_, _):
+ return widen().parents();
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ if (sym.kind == ALIAS)
+ return unalias().parents();
+ else if (sym.kind == CLASS) {
+ assert sym.typeParams().length == args.length : sym + " " + ArrayApply.toString(args);//debug
+ return subst(asSeenFrom(sym.info().parents(), pre, sym.owner()),
+ sym.typeParams(), args);
+ } else
+ return new Type[]{sym.info().asSeenFrom(pre, sym.owner())};
+ case CompoundType(Type[] parts, _):
+ return parts;
+ default:
+ return Type.EMPTY_ARRAY;
+ }
+ }
+
+ /** Get type parameters of polymorphic method
+ * or EMPTY_ARRAY if not applicable.
+ */
+ public Symbol[] typeParams() {
+ switch (this) {
+ case PolyType(Symbol[] tparams, _):
+ return tparams;
+ case TypeRef(_, Symbol sym, _):
+ if (sym.kind == CLASS || sym.kind == ALIAS) return sym.typeParams();
+ break;
+ }
+ return Symbol.EMPTY_ARRAY;
+ }
+
+ /** If this type is a (possibly polymorphic) method type, its result type
+ * after applying all method argument sections,
+ * otherwise the type itself.
+ */
+ public Type resultType() {
+ switch (this) {
+ case PolyType(_, Type tpe):
+ return tpe.resultType();
+ case MethodType(_, Type tpe):
+ return tpe.resultType();
+ default:
+ return this;
+ }
+ }
+
+ /** The number of value parameter sections of this type.
+ */
+ public int paramSectionCount() {
+ switch (this) {
+ case PolyType(_, Type restpe):
+ return restpe.paramSectionCount();
+ case MethodType(_, Type restpe):
+ return restpe.paramSectionCount() + 1;
+ default: return 0;
+ }
+ }
+
+ /** The arity of the first parameter section of this type.
+ */
+ public Symbol[] firstParams() {
+ switch (this) {
+ case PolyType(_, Type restpe):
+ return restpe.firstParams();
+ case MethodType(Symbol[] params, _):
+ return params;
+ default: return Symbol.EMPTY_ARRAY;
+ }
+ }
+
+ /** If this type is overloaded, its alternative types,
+ * otherwise an array consisting of this type itself.
+ */
+ public Type[] alternatives() {
+ switch (this) {
+ case OverloadedType(_, Type[] alttypes):
+ return alttypes;
+ default:
+ return new Type[]{this};
+ }
+ }
+
+ /** If type is a this type of a module class, transform to singletype of
+ * module.
+ */
+ public Type expandModuleThis() {
+ switch (this) {
+ case ThisType(Symbol sym):
+ if ((sym.flags & MODUL) != 0 && sym.module() != Symbol.NONE) {
+ return singleType(
+ sym.owner().thisType().expandModuleThis(), sym.module());
+ }
+ }
+ return this;
+ }
+
+ /** If this is a covariant type, its underlying type, otherwise the type itself.
+ */
+ public Type dropVariance() {
+ switch (this) {
+ case CovarType(Type tp): return tp;
+ default: return this;
+ }
+ }
+
+ public static Map dropVarianceMap = new Map() {
+ public Type apply(Type t) { return t.dropVariance(); }
+ };
+
+// Tests --------------------------------------------------------------------
+
+ /** Is this type a this type or singleton type?
+ */
+ public boolean isStable() {
+ switch (unalias()) {
+ case ThisType(_):
+ case SingleType(_, _):
+ case ErrorType:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /** Is this type a reference to an object type?
+ */
+ public boolean isObjectType() {
+ switch (unalias()) {
+ case ThisType(_):
+ case SingleType(_, _):
+ case CompoundType(_, _):
+ return true;
+ case TypeRef(Type pre, Symbol sym, _):
+ return sym.kind != ALIAS || unalias().isObjectType();
+ default:
+ return false;
+ }
+ }
+
+ /** Is this type a covariant type?
+ */
+ public boolean isCovarType() {
+ switch (this) {
+ case CovarType(_):
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /** Is this type of the form scala.Tuple_N[+T_0, ..., +T_N-1]?
+ */
+ public boolean isTupleType() {
+ switch (this) {
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ if (sym.owner() == Global.instance.definitions.SCALA_CLASS &&
+ sym.name.startsWith(Names.Tuple)) {
+ for (int i = 0; i < args.length; i++)
+ if (!args[i].isCovarType()) return false;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Is this type of the form scala.FunctionN[T_1, ..., T_n, +T]?
+ */
+ public boolean isFunctionType() {
+ switch (this) {
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ if (sym.fullName().startsWith(Names.Function))
+ for (int i = 0; i < args.length - 1; i++)
+ if (args[i].isCovarType()) return false;
+ return args.length > 0 && args[args.length - 1].isCovarType();
+ default:
+ return false;
+ }
+ }
+
+// Members and Lookup -------------------------------------------------------
+
+ /** Get the scope containing the local members of this type.
+ * Symbols in this scope are not prefix-adapted!
+ */
+ public Scope members() {
+ switch (this) {
+ case ErrorType:
+ return new Scope();
+ case TypeRef(_, Symbol sym, _):
+ return sym.info().members();
+ case SingleType(_, Symbol sym):
+ return widen().members();
+ case CompoundType(Type[] basetypes, Scope members):
+ return members;
+ default:
+ return Scope.EMPTY;
+ }
+ }
+
+ /** Lookup symbol with given name among all local and inherited members
+ * of this type; return Symbol.NONE if not found.
+ */
+ public Symbol lookup(Name name) {
+ switch (this) {
+ case ErrorType:
+ return Symbol.ERROR;
+ case ThisType(_):
+ case SingleType(_, _):
+ return widen().lookup(name);
+ case TypeRef(_, Symbol sym, _):
+ return sym.info().lookup(name);
+ case CompoundType(Type[] parts, Scope members):
+ Symbol sym = members.lookup(name);
+ if (sym.kind != NONE) return sym;
+ else return lookupNonPrivate(name);
+ default:
+ return Symbol.NONE;
+ }
+ }
+
+ /** Lookup non-private symbol with given name among all local and
+ * inherited members of this type; return Symbol.NONE if not found.
+ */
+ public Symbol lookupNonPrivate(Name name) {
+ return lookupNonPrivate(name, 0);
+ }
+
+ /** Same as before, but with additional parameter `start'.
+ * If start == 0, lookup in all basetypes of a compound type.
+ * If start == 1, lookup only in mixin classes.
+ */
+ private Symbol lookupNonPrivate(Name name, int start) {
+ switch (this) {
+ case ErrorType:
+ return Symbol.ERROR;
+ case ThisType(_):
+ case SingleType(_, _):
+ return widen().lookupNonPrivate(name);
+ case TypeRef(_, Symbol sym, _):
+ return sym.info().lookupNonPrivate(name, start);
+ case CompoundType(Type[] parts, Scope members):
+ Symbol sym = members.lookup(name);
+ if (sym.kind != NONE && (sym.flags & PRIVATE) == 0)
+ return sym;
+
+ // search base types in reverse; non-abstract members
+ // take precedence over abstract ones.
+ int i = parts.length;
+ sym = Symbol.NONE;
+ while (i > start && (sym.kind == NONE || (sym.flags & ABSTRACT) != 0)) {
+ i--;
+ Symbol sym1 = parts[i].lookupNonPrivate(name, i == 0 ? 0 : 1);
+ if (sym1.kind != NONE &&
+ (sym1.flags & PRIVATE) == 0 &&
+ (sym.kind == NONE || (sym1.flags & ABSTRACT) == 0))
+ sym = sym1;
+ }
+ return sym;
+ default:
+ return Symbol.NONE;
+ }
+ }
+
+// Maps --------------------------------------------------------------------------
+
+ /** The type of type-to-type functions.
+ */
+ public abstract static class Map {
+
+ boolean covariantOK = true;
+
+ public abstract Type apply(Type t);
+
+ /** Apply map to all top-level components of this type.
+ */
+ public Type map(Type tp) {
+ switch (tp) {
+ case ErrorType:
+ case AnyType:
+ case NoType:
+ case UnboxedType(_):
+ case TypeVar(_, _):
+ case ThisType(_):
+ return tp;
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ Type pre1 = map(pre);
+ Type[] args1 = map(args);
+ if (pre1 == pre && args1 == args) return tp;
+ else return TypeRef(pre1, sym, args1);
+ case SingleType(Type pre, Symbol sym):
+ Type pre1 = map(pre);
+ if (pre1 == pre) return tp;
+ else return singleType(pre1, sym);
+ case CompoundType(Type[] parts, Scope members):
+ Type[] parts1 = map(parts);
+ Scope members1 = map(members);
+ if (parts1 == parts && members1 == members) {
+ return tp;
+ } else {
+ Scope members2 = new Scope();
+ Type tp1 = (tp.symbol().isCompoundSym()) ? compoundType(parts1, members2)
+ : compoundType(parts1, members2, tp.symbol());
+ Symbol[] syms1 = members1.elements();
+ Symbol[] syms2 = new Symbol[syms1.length];
+ for (int i = 0; i < syms2.length; i++) {
+ syms2[i] = syms1[i].cloneSymbol().setOwner(tp1.symbol());
+ }
+ for (int i = 0; i < syms2.length; i++) {
+ syms2[i].setInfo(syms1[i].info().subst(syms1, syms2));
+ }
+ for (int i = 0; i < syms2.length; i++) {
+ members2.enter(syms2[i]);
+ }
+ return tp1;
+ }
+
+ case MethodType(Symbol[] vparams, Type result):
+ covariantOK = false;
+ Symbol[] vparams1 = map(vparams);
+ covariantOK = true;
+ Type result1 = apply(result);
+ if (vparams1 == vparams && result1 == result) return tp;
+ else return MethodType(vparams1, result1);
+ case PolyType(Symbol[] tparams, Type result):
+ covariantOK = false;
+ Symbol[] tparams1 = map(tparams);
+ covariantOK = true;
+ Type result1 = apply(result);
+ if (tparams1 != tparams) result1 = result1.subst(tparams, tparams1);
+ if (tparams1 == tparams && result1 == result) return tp;
+ else return PolyType(tparams1, result1);
+ case OverloadedType(Symbol[] alts, Type[] alttypes):
+ Type[] alttypes1 = map(alttypes);
+ if (alttypes1 == alttypes) return tp;
+ else return OverloadedType(alts, alttypes1);
+ case CovarType(Type t):
+ Type t1 = apply(t);
+ if (t1 == t) return tp;
+ else return covarType(t1);
+ case UnboxedArrayType(Type elemtp):
+ Type elemtp1 = apply(elemtp);
+ if (elemtp1 == elemtp) return tp;
+ else return UnboxedArrayType(elemtp1);
+ default:
+ throw new ApplicationError(tp);
+ }
+ }
+
+ public Symbol map(Symbol sym) {
+ Type tp = sym.info();
+ Type tp1 = apply(tp);
+ if (tp == tp1) return sym;
+ else return sym.cloneSymbol().setInfo(tp1);
+ }
+
+ public Type[] map(Type[] tps) {
+ Type[] tps1 = tps;
+ for (int i = 0; i < tps.length; i++) {
+ Type tp = tps[i];
+ Type tp1 = apply(tp);
+ if (tp1 != tp && tps1 == tps) {
+ tps1 = new Type[tps.length];
+ System.arraycopy(tps, 0, tps1, 0, i);
+ }
+ tps1[i] = tp1;
+ }
+ return tps1;
+ }
+
+ /** Apply map to all elements of this array of symbols,
+ * preserving recursive references to symbols in the array.
+ */
+ public Symbol[] map(Symbol[] syms) {
+ Symbol[] syms1 = syms;
+ for (int i = 0; i < syms.length; i++) {
+ Symbol sym = syms[i];
+ Symbol sym1 = map(sym);
+ if (sym != sym1 && syms1 == syms) {
+ syms1 = new Symbol[syms.length];
+ System.arraycopy(syms, 0, syms1, 0, i);
+ }
+ syms1[i] = sym1;
+ }
+ if (syms1 != syms) {
+ for (int i = 0; i < syms1.length; i++) {
+ if (syms1[i] == syms[i])
+ syms1[i] = syms[i].cloneSymbol();
+ }
+ for (int i = 0; i < syms1.length; i++) {
+ syms1[i].setInfo(syms1[i].info().subst(syms, syms1));
+ }
+ }
+ return syms1;
+ }
+
+ /** Apply map to all elements of this array of this scope.
+ */
+ public Scope map(Scope s) {
+ Symbol[] members = s.elements();
+ Symbol[] members1 = map(members);
+ if (members == members1) return s;
+ else return new Scope(members1);
+ }
+ }
+
+// baseType and asSeenFrom --------------------------------------------------------
+
+ /** Return the base type of this type whose symbol is `clazz', or NoType, if
+ * such a type does not exist.
+ */
+ public Type baseType(Symbol clazz) {
+ //System.out.println(this + ".baseType(" + clazz + ")");//DEBUG
+ switch (this) {
+ case ErrorType:
+ return ErrorType;
+
+ case ThisType(_):
+ case SingleType(_, _):
+ return widen().baseType(clazz);
+
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ if (sym == clazz)
+ return this;
+ else if (sym.kind == TYPE)
+ return pre.memberInfo(sym).baseType(clazz);
+ else if (sym.kind == ALIAS)
+ return pre.memberInfo(sym).baseType(clazz)
+ .subst(sym.typeParams(), args);
+ else if (clazz.isCompoundSym())
+ return NoType;
+ else
+ return sym.baseType(clazz)
+ .asSeenFrom(pre, clazz.owner())
+ .subst(sym.typeParams(), args);
+
+ case CompoundType(Type[] parts, _):
+ for (int i = parts.length - 1; i >= 0; i--) {
+ Type result = parts[i].baseType(clazz);
+ if (result != NoType) return result;
+ }
+ break;
+
+ case UnboxedArrayType(_):
+ if (clazz == Global.instance.definitions.ANY_CLASS)
+ return clazz.type();
+ }
+ return NoType;
+ }
+
+ /** Return overriding instance of `sym' in this type,
+ * or `sym' itself if none exists.
+ */
+ public Symbol rebind(Symbol sym) {
+ Symbol sym1 = lookupNonPrivate(sym.name);
+ if (sym1.kind != NONE) {
+ //System.out.println("rebinding " + sym + " to " + sym1);//DEBUG
+ return sym1;
+ }
+ else return sym;
+ }
+
+ /** A map to implement `asSeenFrom'.
+ */
+ static class AsSeenFromMap extends Map {
+
+ private Type pre;
+ private Symbol clazz;
+ private Type illegalType = NoType;
+ private boolean typeArg = false;
+
+ AsSeenFromMap(Type pre, Symbol clazz) {
+ this.pre = pre; this.clazz = clazz;
+ }
+
+ public Type apply(Type t) {
+ switch (t) {
+ case ThisType(Symbol sym):
+ return t.toPrefix(pre, clazz);
+
+ case TypeRef(Type prefix, Symbol sym, Type[] args):
+ if (sym.kind == ALIAS) {
+ return apply(t.unalias());
+ } else if (sym.owner().isPrimaryConstructor()) {
+ assert sym.kind == TYPE;
+ Type t1 = t.toInstance(pre, clazz);
+ //System.out.println(t + ".toInstance(" + pre + "," + clazz + ") = " + t1);//DEBUG
+ switch (t1) {
+ case CovarType(Type tp):
+ if (!covariantOK) {
+ if (illegalType == NoType) illegalType = t1;
+ } else if (!typeArg) {
+ t1 = tp;
+ }
+ }
+ return t1;
+ } else {
+ Type prefix1 = prefix.toPrefix(pre, clazz);
+ Symbol sym1 = (prefix1 == prefix || (sym.flags & MODUL) != 0)
+ ? sym : prefix1.rebind(sym);
+ boolean prevTypeArg = typeArg;
+ typeArg = true;
+ Type[] args1 = map(args);
+ typeArg = prevTypeArg;
+ if (prefix1 == prefix && args1 == args) return t;
+ else return TypeRef(prefix1, sym1, args1);
+ }
+
+ case SingleType(Type prefix, Symbol sym):
+ try {
+ Type prefix1 = prefix.toPrefix(pre, clazz);
+ if (prefix1 == prefix) return t;
+ else return singleType(prefix1, prefix1.rebind(sym));
+ } catch (Type.Error ex) {
+ return apply(t.widen());
+ }
+ break;
+
+ default:
+ return map(t);
+ }
+ }
+
+ void checkLegal(Type tp) {
+ if (illegalType != NoType) {
+ throw new ApplicationError(
+ "malformed type: " + tp + "; " +
+ illegalType + " does not occur in covariant position");
+ }
+ }
+ }
+ //where
+ Type toInstance(Type pre, Symbol clazz) {
+ if (pre == NoType || clazz.kind != CLASS)
+ return this;
+ Symbol sym = symbol();
+ Symbol ownclass = sym.owner().constructorClass();
+ if (ownclass.isSubClass(clazz) &&
+ pre.symbol().isSubClass(ownclass)) {
+ switch (pre.baseType(ownclass)) {
+ case TypeRef(_, Symbol basesym, Type[] baseargs):
+ Symbol[] baseparams = basesym.typeParams();
+ for (int i = 0; i < baseparams.length; i++)
+ if (sym == baseparams[i]) return baseargs[i];//???
+ break;
+ case ErrorType:
+ return ErrorType;
+ }
+ throw new ApplicationError(
+ this + " cannot be instantiated from " + pre);
+ } else {
+ return toInstance(
+ pre.baseType(clazz).prefix(), clazz.owner());
+ }
+ }
+
+ Type toPrefix(Type pre, Symbol clazz) {
+ if (pre == NoType || clazz.kind != CLASS)
+ return this;
+ if (symbol().isSubClass(clazz) &&
+ pre.symbol().isSubClass(symbol())) {
+ if (!pre.isStable()) {
+ throw new Type.Error (
+ "malformed type: " + pre + "." + symbol().nameString());
+ }
+ return pre;
+ } else {
+ return toPrefix(
+ pre.baseType(clazz).prefix(), clazz.owner());
+ }
+ }
+
+ /** This type Types as seen from prefix `pre' and class `clazz'. This means:
+ * Replace all this thistypes of `clazz' or one of its superclasses by `pre'.
+ * Proceed analogously for thistypes referring to outer classes.
+ */
+ public Type asSeenFrom(Type pre, Symbol clazz) {
+ //System.out.println("computing asseenfrom of " + this + " with " + pre + "," + clazz);//DEBUG
+ AsSeenFromMap f = new AsSeenFromMap(pre, clazz);
+ Type t = f.apply(this);
+ f.checkLegal(t);
+ return t;
+ }
+
+ /** Types `these' as seen from prefix `pre' and class `clazz'.
+ */
+ public static Type[] asSeenFrom(Type[] these, Type pre, Symbol clazz) {
+ AsSeenFromMap f = new AsSeenFromMap(pre, clazz);
+ Type[] these1 = f.map(these);
+ for (int i = 0; i < these1.length; i++)
+ f.checkLegal(these1[i]);
+ return these1;
+ }
+
+ /** The info of `sym', seen as a member of this type.
+ */
+ public Type memberInfo(Symbol sym) {
+ return memberTransform(sym, sym.info());
+ }
+
+ /** The type of `sym', seen as a member of this type.
+ */
+ public Type memberType(Symbol sym) {
+ return memberTransform(sym, sym.type());
+ }
+
+ private Type memberTransform(Symbol sym, Type tp) {
+ Type tp1 = tp.asSeenFrom(narrow(), sym.owner());
+ Type tp2 = tp1.asSeenFrom(this, widen().symbol());
+ //todo: sym.owner()?
+ //if (Global.instance.debug) System.out.println(this + "/" + widen() + ".memberType(" + sym + ":" + tp + ") = " + tp1 + "/" + tp2);//DEBUG
+ return tp2;
+ }
+
+// Substitutions ---------------------------------------------------------------
+
+ /** A common map superclass for symbol/symbol and type/symbol substitutions.
+ */
+ static abstract class SubstMap extends Map {
+ private Symbol[] from;
+
+ SubstMap(Symbol[] from) {
+ this.from = from;
+ }
+
+ /** Produce replacement type
+ * @param i The index in `from' of the symbol to be replaced.
+ * @param fromtp The type referring to this symbol.
+ */
+ abstract Type replacement(int i, Type fromtp);
+
+ /** Produce new substitution where some symbols are excluded.
+ * @param newfrom The new array of from symbols (without excluded syms)
+ * @param excluded The array of excluded sysmbols
+ */
+ abstract SubstMap exclude(Symbol[] newfrom, Symbol[] excluded);
+
+ public Type apply(Type t) {
+ switch (t) {
+ case TypeRef(ThisType(_), Symbol sym, Type[] args):
+ for (int i = 0; i < from.length; i++) {
+ if (sym == from[i]) return replacement(i, t);
+ }
+ break;
+ case SingleType(ThisType(_), Symbol sym):
+ for (int i = 0; i < from.length; i++) {
+ if (sym == from[i]) return replacement(i, t);
+ }
+ break;
+ case PolyType(Symbol[] tparams, Type result):
+ Symbol[] from1 = excludeSyms(from, tparams, from);
+ if (from1 != from) {
+ SubstMap f = exclude(from1, tparams);
+ Symbol[] tparams1 = f.map(tparams);
+ Type result1 = f.apply(result);
+ if (tparams1 != tparams)
+ result1 = result1.subst(tparams, tparams1);
+ if (tparams1 == tparams && result1 == result) return t;
+ else return PolyType(tparams1, result1);
+ }
+ }
+ return map(t);
+ }
+ //where
+ private boolean contains1(Symbol[] syms, Symbol sym) {
+ int i = 0;
+ while (i < syms.length && syms[i] != sym) i++;
+ return i < syms.length;
+ }
+
+ private int nCommon(Symbol[] from, Symbol[] tparams) {
+ int cnt = 0;
+ for (int i = 0; i < from.length; i++) {
+ if (contains1(tparams, from[i])) cnt++;
+ }
+ return cnt;
+ }
+
+ private Symbol[] excludeSyms(Symbol[] from, Symbol[] tparams, Symbol[] syms) {
+ int n = nCommon(from, tparams);
+ if (n == 0) {
+ return syms;
+ } else {
+ Symbol[] syms1 = new Symbol[syms.length - n];
+ int j = 0;
+ for (int i = 0; i < from.length; i++) {
+ if (!contains1(tparams, from[i])) syms1[j++] = syms[i];
+ }
+ return syms1;
+ }
+ }
+
+ private Type[] excludeTypes(Symbol[] from, Symbol[] tparams, Type[] types) {
+ int n = nCommon(from, tparams);
+ if (n == 0) {
+ return types;
+ } else {
+ Type[] types1 = new Type[types.length - n];
+ int j = 0;
+ for (int i = 0; i < from.length; i++) {
+ if (!contains1(tparams, from[i])) types1[j++] = types[i];
+ }
+ return types1;
+ }
+ }
+ }
+
+ /** A map for symbol/symbol substitutions
+ */
+ static class SubstSymMap extends SubstMap {
+ Symbol[] to;
+ SubstSymMap(Symbol[] from, Symbol[] to) {
+ super(from);
+ this.to = to;
+ }
+ Type replacement(int i, Type fromtp) {
+ switch (fromtp) {
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ return TypeRef(pre, to[i], args);
+ case SingleType(Type pre, Symbol sym):
+ return singleType(pre, to[i]);
+ default:
+ throw new ApplicationError();
+ }
+ }
+ SubstMap exclude(Symbol[] newfrom, Symbol[] excluded) {
+ return new SubstSymMap(newfrom, excludeSyms(from, excluded, to));
+ }
+ }
+
+ /** A map for type/symbol substitutions
+ */
+ static class SubstTypeMap extends SubstMap {
+ Type[] to;
+ SubstTypeMap(Symbol[] from, Type[] to) {
+ super(from);
+ this.to = to;
+ }
+ Type replacement(int i, Type fromtp) {
+ return to[i];
+ }
+ SubstMap exclude(Symbol[] newfrom, Symbol[] excluded) {
+ return new SubstTypeMap(newfrom, excludeTypes(from, excluded, to));
+ }
+ }
+
+ /** Substitute symbols `to' for occurrences of symbols `from' in this type.
+ */
+ public Type subst(Symbol[] from, Symbol[] to) {
+ assert from.length == to.length
+ : this + ": " + from.length + " != " + to.length;
+ if (from.length != 0 && from != to)
+ return new SubstSymMap(from, to).apply(this);
+ else return this;
+ }
+
+ /** Substitute symbols `to' for occurrences of symbols `from' in these types.
+ */
+ public static Type[] subst(Type[] these, Symbol[] from, Symbol[] to) {
+ assert from.length == to.length;
+ if (these.length != 0 && from.length != 0 && from != to)
+ return new SubstSymMap(from, to).map(these);
+ else return these;
+ }
+
+ /** Substitute types `to' for occurrences of symbols `from' in this type.
+ */
+ public Type subst(Symbol[] from, Type[] to) {
+ assert from.length == to.length
+ : this + ": " + from.length + " != " + to.length;
+ if (from.length != 0)
+ return new SubstTypeMap(from, to).apply(this);
+ else return this;
+ }
+
+ /** Substitute types `to' for occurrences of symbols `from' in these types.
+ */
+ public static Type[] subst(Type[] these, Symbol[] from, Type[] to) {
+ assert from.length == to.length;
+ if (these.length != 0 && from.length != 0)
+ return new SubstTypeMap(from, to).map(these);
+ else return these;
+ }
+
+ /** A map for substitutions of thistypes.
+ */
+ static class SubstThisMap extends Map {
+ Symbol from;
+ Type to;
+ SubstThisMap(Symbol from, Type to) {
+ this.from = from;
+ this.to = to;
+ }
+ public Type apply(Type t) {
+ switch (t) {
+ case ThisType(Symbol sym):
+ if (sym == from) return to;
+ else return t;
+ default:
+ return map(t);
+ }
+ }
+ }
+
+ public Type substThis(Symbol from, Type to) {
+ return new SubstThisMap(from, to).apply(this);
+ }
+
+ public static Type[] substThis(Type[] these, Symbol from, Type to) {
+ return new SubstThisMap(from, to).map(these);
+ }
+
+ static class ContainsMap extends Map {
+ boolean result = false;
+ Symbol sym;
+ ContainsMap(Symbol sym) {
+ this.sym = sym;
+ }
+ public Type apply(Type t) {
+ switch (t) {
+ case TypeRef(Type pre, Symbol sym1, Type[] args):
+ if (sym == sym1) result = true;
+ else { map(pre); map(args); }
+ break;
+ case SingleType(Type pre, Symbol sym1):
+ map(pre);
+ if (sym == sym1) result = true;
+ break;
+ default:
+ map(t);
+ }
+ return t;
+ }
+ }
+
+ /** Does this type contain symbol `sym'?
+ */
+ public boolean contains(Symbol sym) {
+ ContainsMap f = new ContainsMap(sym);
+ f.apply(this);
+ return f.result;
+ }
+
+ /** Does this type contain any of the symbols `syms'?
+ */
+ public boolean containsSome(Symbol[] syms) {
+ for (int i = 0; i < syms.length; i++)
+ if (contains(syms[i])) return false;
+ return true;
+ }
+
+// Comparisons ------------------------------------------------------------------
+
+ /** Is this type a subtype of that type?
+ */
+ public boolean isSubType(Type that) {
+ if (debugSwitch) {
+ for (int i = 0; i < indent; i++) System.out.print(" ");
+ System.out.println(this + " < " + that + "?");
+ indent++;
+ }
+ boolean result = isSubType0(that);
+ if (debugSwitch) {
+ indent--;
+ for (int i = 0; i < indent; i++) System.out.print(" ");
+ System.out.println(result);
+ }
+ return result;
+ }
+
+ public boolean isSubType0(Type that) {
+ if (this == that) return true;
+
+ switch (this) {
+ case ErrorType:
+ case AnyType:
+ return true;
+ }
+
+ switch (that) {
+ case ErrorType:
+ case AnyType:
+ return true;
+
+ case NoType:
+ return false;
+
+ case ThisType(Symbol sym1):
+ switch (this) {
+ case ThisType(Symbol sym):
+ return sym == sym1;
+ case SingleType(Type pre, Symbol sym):
+ return sym.isModule()
+ && sym.moduleClass() == sym1
+ && pre.isSameAs(sym1.owner().thisType());
+ }
+ break;
+
+ case SingleType(Type pre1, Symbol sym1):
+ switch (this) {
+ case SingleType(Type pre, Symbol sym):
+ return sym == sym1 && pre.isSameAs(pre1);
+ case ThisType(Symbol sym):
+ return sym1.isModule()
+ && sym == sym1.moduleClass()
+ && sym.owner().thisType().isSameAs(pre1);
+ }
+ break;
+
+ case TypeRef(Type pre1, Symbol sym1, Type[] args1):
+ switch (this) {
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ if (sym == sym1 && pre.isSameAs(pre1) && isSubArgs(args, args1))
+ return true;
+ break;
+ }
+ if (sym1.kind == CLASS) {
+ Type base = this.baseType(sym1);
+ if (this != base && base.isSubType(that))
+ return true;
+ }
+ break;
+
+ case CompoundType(Type[] parts1, Scope members1):
+ int i = 0;
+ while (i < parts1.length && isSubType(parts1[i])) i++;
+ if (i == parts1.length && specializes(members1))
+ return true;
+ break;
+
+ case MethodType(Symbol[] ps1, Type res1):
+ switch (this) {
+ case MethodType(Symbol[] ps, Type res):
+ if (ps.length != ps1.length) return false;
+ for (int i = 0; i < ps.length; i++) {
+ Symbol p1 = ps1[i];
+ Symbol p = ps[i];
+ if (!p1.type().isSubType(p.type()) ||
+ (p1.flags & Modifiers.DEF) != (p.flags & Modifiers.DEF))
+ return false;
+ }
+ return res.isSubType(res1);
+ }
+ break;
+
+ case PolyType(Symbol[] ps1, Type res1):
+ switch (this) {
+ case PolyType(Symbol[] ps, Type res):
+ if (ps.length != ps1.length) return false;
+ for (int i = 0; i < ps.length; i++)
+ if (!ps1[i].info().subst(ps1, ps).isSubType(ps[i].info()))
+ return false;
+ return res.isSubType(res1.subst(ps1, ps));
+ }
+ break;
+
+ case OverloadedType(Symbol[] alts1, Type[] alttypes1):
+ if (isSubSet(alttypes1, alternatives()))
+ return true;
+ break;
+
+ case UnboxedType(int tag1):
+ switch (this) {
+ case UnboxedType(int tag):
+ return tag <= tag1 && tag1 <= DOUBLE && tag1 != CHAR;
+ }
+ break;
+
+ case UnboxedArrayType(Type elemtp1):
+ switch (this) {
+ case UnboxedArrayType(Type elemtp):
+ return !(elemtp1 instanceof UnboxedType) && elemtp.isSubType(elemtp1);
+ }
+ break;
+
+ case TypeVar(Type origin, Constraint constr):
+ //todo: should we test for equality with origin?
+ if (constr.inst != NoType) {
+ return this.isSubType(constr.inst);
+ } else if (!this.isCovarType()) {
+ constr.lobounds = new List(this, constr.lobounds);
+ return true;
+ }
+ break;
+
+ default:
+ throw new ApplicationError(this + " <: " + that);
+ }
+
+ switch (this) {
+ case NoType:
+ return false;
+ case ThisType(_):
+ case SingleType(_, _):
+ if (this.widen().isSubType(that)) return true;
+ break;
+ case TypeVar(Type origin, Constraint constr):
+ if (constr.inst != NoType) {
+ return constr.inst.isSubType(that);
+ } else {
+ constr.hibounds = new List(that.dropVariance(), constr.hibounds);
+ return true;
+ }
+
+ case TypeRef(_, Symbol sym, _):
+ if (sym.kind == ALIAS) return this.unalias().isSubType(that);
+ break;
+
+ case OverloadedType(Symbol[] alts, Type[] alttypes):
+ for (int i = 0; i < alttypes.length; i++) {
+ if (alttypes[i].isSameAs0(that)) return true;
+ }
+ break;
+ }
+
+ switch (that) {
+ case TypeRef(_, Symbol sym1, _):
+ if (sym1.kind == ALIAS) return this.isSubType(that.unalias());
+ break;
+ }
+
+ return false;
+ }
+
+ /** Are types `these' subtypes of corresponding types `those'?
+ */
+ public static boolean isSubType(Type[] these, Type[] those) {
+ if (these.length != those.length) return false;
+ for (int i = 0; i < these.length; i++) {
+ if (!these[i].isSubType(those[i])) return false;
+ }
+ return true;
+ }
+
+ /** Are types `these' arguments types conforming to corresponding types `those'?
+ */
+ static boolean isSubArgs(Type[] these, Type[] those) {
+ if (these.length != those.length) return false;
+ for (int i = 0; i < these.length; i++) {
+ switch (those[i]) {
+ case CovarType(Type tp1):
+ switch (these[i]) {
+ case CovarType(Type tp):
+ if (!tp.isSubType(tp1)) return false;
+ break;
+ default:
+ if (!these[i].isSubType(tp1)) return false;
+ }
+ break;
+ default:
+ if (these[i].isCovarType() || !these[i].isSameAs(those[i]))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static boolean isSubSet(Type[] alts, Type[] alts1) {
+ for (int i = 0; i < alts.length; i++) {
+ int j = 0;
+ while (j < alts1.length && !alts1[j].isSameAs(alts[i])) j++;
+ if (j == alts1.length) return false;
+ }
+ return true;
+ }
+
+ /** Does this type implement all symbols in scope `s' with same or stronger types?
+ */
+ public boolean specializes(Scope s) {
+ for (Scope.Entry e = s.elems; e != Scope.Entry.NONE; e = e.next)
+ if (!specializes(e.sym)) return false;
+ return true;
+ }
+
+ /** Does this type implement symbol `sym1' with same or stronger type?
+ */
+ public boolean specializes(Symbol sym1) {
+ if (debugSwitch) {
+ for (int i = 0; i < indent; i++) System.out.print(" ");
+ System.out.println(this + " specializes " + sym1 + "?");
+ indent++;
+ }
+ boolean result = specializes0(sym1);
+ if (debugSwitch) {
+ indent--;
+ for (int i = 0; i < indent; i++) System.out.print(" ");
+ System.out.println(result);
+ }
+ return result;
+ }
+
+ public boolean specializes0(Symbol sym1) {
+ Symbol sym = lookup(sym1.name);
+ Type self = narrow();
+ return
+ sym == sym1 ||
+ ((sym.kind == sym1.kind || sym1.kind == TYPE) &&
+ self.memberInfo(sym).isSubType(
+ sym1.info().substThis(sym.owner(), self))) ||
+ (sym.kind == TYPE && sym1.kind == ALIAS &&
+ sym1.info().unalias().isSameAs(sym.type()));
+ }
+
+ /** Is this type the same as that type?
+ */
+ public boolean isSameAs(Type that) {
+ if (debugSwitch) {
+ for (int i = 0; i < indent; i++) System.out.print(" ");
+ System.out.println(this + " = " + that + "?");
+ indent++;
+ }
+ boolean result = isSameAs0(that);
+ if (debugSwitch) {
+ indent--;
+ for (int i = 0; i < indent; i++) System.out.print(" ");
+ System.out.println(result);
+ }
+ return result;
+ }
+
+ public boolean isSameAs0(Type that) {
+ if (this == that) return true;
+
+ switch (this) {
+ case ErrorType:
+ case AnyType:
+ return true;
+
+ case ThisType(Symbol sym):
+ switch (that) {
+ case ThisType(Symbol sym1):
+ return sym == sym1;
+ case SingleType(Type pre1, Symbol sym1):
+ return sym1.isModule()
+ && sym == sym1.moduleClass()
+ && sym.owner().thisType().isSameAs(pre1);
+ }
+ break;
+
+ case SingleType(Type pre, Symbol sym):
+ switch (that) {
+ case SingleType(Type pre1, Symbol sym1):
+ return sym == sym1 && pre.isSameAs(pre1);
+ case ThisType(Symbol sym1):
+ return sym.isModule()
+ && sym.moduleClass() == sym1
+ && pre.isSameAs(sym1.owner().thisType());
+ }
+ break;
+
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ switch (that) {
+ case TypeRef(Type pre1, Symbol sym1, Type[] args1):
+ if (sym == sym1 && pre.isSameAs(pre1) && isSameArgs(args, args1))
+ return true;
+ }
+ break;
+
+ case CompoundType(Type[] parts, Scope members):
+ switch (that) {
+ case CompoundType(Type[] parts1, Scope members1):
+ if (parts.length != parts1.length) return false;
+ for (int i = 0; i < parts.length; i++)
+ if (!parts[i].isSameAs(parts1[i])) return false;
+ return isSameAs(members, members1);
+ }
+ break;
+
+ case MethodType(Symbol[] ps, Type res):
+ switch (that) {
+ case MethodType(Symbol[] ps1, Type res1):
+ if (ps.length != ps1.length) return false;
+ for (int i = 0; i < ps.length; i++) {
+ Symbol p1 = ps1[i];
+ Symbol p = ps[i];
+ if (!p1.type().isSameAs(p.type()) ||
+ (p1.flags & Modifiers.DEF) != (p.flags & Modifiers.DEF))
+ return false;
+ }
+ return res.isSameAs(res1);
+ }
+ break;
+
+ case PolyType(Symbol[] ps, Type res):
+ switch (that) {
+ case PolyType(Symbol[] ps1, Type res1):
+ if (ps.length != ps1.length) return false;
+ for (int i = 0; i < ps.length; i++)
+ if (!ps1[i].info().subst(ps1, ps).isSameAs(ps[i].info()))
+ return false;
+ return res.isSameAs(res1.subst(ps1, ps));
+ }
+ break;
+
+ case OverloadedType(Symbol[] alts, Type[] alttypes):
+ switch (that) {
+ case OverloadedType(Symbol[] alts1, Type[] alttypes1):
+ return isSubSet(alttypes1, alttypes)
+ && isSubSet(alttypes, alttypes1);
+ }
+ break;
+
+ case UnboxedType(int kind):
+ switch (that) {
+ case UnboxedType(int kind1):
+ return kind == kind1;
+ }
+ break;
+
+ case UnboxedArrayType(Type elemtp):
+ switch (that) {
+ case UnboxedArrayType(Type elemtp1):
+ return elemtp.isSameAs(elemtp1);
+ }
+ break;
+ }
+
+ switch (that) {
+ case ErrorType:
+ case AnyType:
+ return true;
+ case NoType:
+ return false;
+ case TypeVar(Type origin, Constraint constr):
+ if (constr.inst != NoType)
+ return constr.inst.isSameAs(this);
+ else if (!this.isCovarType())
+ return constr.instantiate(this.any2typevar());
+ }
+
+ switch (this) {
+ case NoType:
+ return false;
+ case TypeVar(Type origin, Constraint constr):
+ if (constr.inst != NoType)
+ return constr.inst.isSameAs(that);
+ else if (!that.isCovarType())
+ return constr.instantiate(that.any2typevar());
+ break;
+ case TypeRef(_, Symbol sym, _):
+ if (sym.kind == ALIAS) return this.unalias().isSameAs(that);
+ }
+
+ switch (that) {
+ case TypeRef(_, Symbol sym, _):
+ if (sym.kind == ALIAS) return this.isSameAs(that.unalias());
+ }
+
+ return false;
+ }
+
+ /** Is this type argument that same as `that'?
+ */
+ public boolean isSameArg(Type that) {
+ switch (this) {
+ case CovarType(Type tp):
+ switch (that) {
+ case CovarType(Type tp1):
+ return tp.isSameAs(tp1);
+ }
+ }
+ return this.isSameAs(that);
+ }
+
+ /** Are types `these' the same as corresponding types `those'?
+ */
+ public static boolean isSameAs(Type[] these, Type[] those) {
+ if (these.length != those.length) return false;
+ for (int i = 0; i < these.length; i++) {
+ if (!these[i].isSameAs(those[i])) return false;
+ }
+ return true;
+ }
+
+ /** Are type arguments `these' the same as corresponding types `those'?
+ */
+ public static boolean isSameArgs(Type[] these, Type[] those) {
+ if (these.length != those.length) return false;
+ for (int i = 0; i < these.length; i++) {
+ if (!these[i].isSameArg(those[i])) return false;
+ }
+ return true;
+ }
+
+ /** Do scopes `s1' and `s2' define he same symbols with the same kinds and infos?
+ */
+ public boolean isSameAs(Scope s1, Scope s2) {
+ return isSubScope(s1, s2) && isSubScope(s2, s1);
+ }
+
+ /** Does scope `s1' define all symbols of scope `s2' with the same kinds and infos?
+ */
+ private boolean isSubScope(Scope s1, Scope s2) {
+ for (Scope.Entry e = s2.elems; e != Scope.Entry.NONE; e = e.next) {
+ Symbol sym2 = e.sym;
+ Symbol sym1 = s1.lookup(sym2.name);
+ if (sym1.kind != sym2.kind ||
+ !sym1.info().isSameAs(
+ sym2.info().substThis(sym2.owner(), sym1.owner().thisType())))
+ return false;
+ }
+ return true;
+ }
+
+ boolean isSameAsAll(Type[] tps) {
+ int i = 1;
+ while (i < tps.length && isSameAs(tps[i])) i++;
+ return i == tps.length;
+ }
+
+ /** Map every occurrence of AnyType to a fresh type variable.
+ */
+ public static Map any2typevarMap = new Map() {
+ public Type apply(Type t) { return t.any2typevar(); }
+ };
+
+ public Type any2typevar() {
+ switch (this) {
+ case AnyType:
+ return TypeVar(this, new Constraint());
+ default:
+ return any2typevarMap.map(this);
+ }
+ }
+
+// Closures and Least Upper Bounds ---------------------------------------------------
+
+ /** The closure of this type, i.e. the widened type itself followed by all
+ * its direct and indirect (pre-) base types, sorted by Symbol.isLess().
+ * Note that (pre-) base types do _not_ carry type parameters; these
+ * are added by baseType().
+ */
+ public Type[] closure() {
+ switch (this.widen().unalias()) {
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ return subst(
+ asSeenFrom(sym.closure(), pre, sym.owner()),
+ sym.typeParams(), args);
+
+ case CompoundType(Type[] parts, Scope members):
+ Type[][] closures = new Type[parts.length][];
+ for (int i = 0; i < parts.length; i++)
+ closures[i] = parts[i].closure();
+ return union(closures);
+
+ default:
+ return new Type[]{this};
+ }
+ }
+
+ /** return union of array of closures
+ */
+ static private Type[] union(Type[][] closures) {
+ if (closures.length == 1) return closures[0]; // fast special case
+ int[] index = new int[closures.length];
+ int totalsize = 0;
+ for (int i = 0; i < index.length; i++) {
+ index[i] = 0;
+ totalsize = totalsize + closures[i].length;
+ }
+ Type[] res = new Type[totalsize];
+ int j = 0;
+
+ while (true) {
+ // find minimal element
+ Type min = null;
+ for (int i = 0; i < index.length; i++) {
+ if (index[i] < closures[i].length) {
+ Type cltype = closures[i][index[i]];
+ if (min == null ||
+ cltype.symbol().isLess(min.symbol()) ||
+ cltype.symbol() == min.symbol() && cltype.isSubType(min)) {
+ min = cltype;
+ }
+ }
+ }
+ if (min == null) break;
+
+ res[j] = min;
+ j = j + 1;
+
+ // bump all indices that start with minimal element
+ for (int i = 0; i < index.length; i++) {
+ if (index[i] < closures[i].length &&
+ closures[i][index[i]].symbol() == min.symbol())
+ index[i] = index[i] + 1;
+ }
+ }
+ Type[] result = new Type[j];
+ System.arraycopy(res, 0, result, 0, j);
+ return result;
+ }
+
+ /** return intersection of array of closures
+ */
+ static private Type[] intersection(Type[][] closures) {
+ if (closures.length == 1) return closures[0]; // fast special case
+ int[] index = new int[closures.length];
+ Type[] mintypes = new Type[closures.length];
+ int minsize = Integer.MAX_VALUE;
+ for (int i = 0; i < index.length; i++) {
+ index[i] = 0;
+ if (closures[i].length < minsize) minsize = closures[i].length;
+ }
+ Type[] res = new Type[minsize];
+ int j = 0;
+
+ L:
+ while (true) {
+ // find minimal element
+ Symbol min = null;
+ for (int i = 0; i < index.length; i++) {
+ if (index[i] == closures[i].length) break L;
+ Symbol clsym = closures[i][index[i]].symbol();
+ if (min == null || clsym.isLess(min)) min = clsym;
+ }
+
+ boolean agree = true;
+ // bump all indices that start with minimal element
+ for (int i = 0; i < index.length; i++) {
+ Type cltype = closures[i][index[i]];
+ if (cltype.symbol() == min) {
+ mintypes[i] = cltype;
+ index[i] = index[i] + 1;
+ } else {
+ agree = false;
+ }
+ }
+ if (agree) {
+ Type mintype;
+ mintype = commonType(mintypes);
+ if (mintype == NoType)
+ mintype = arglub(mintypes);
+ if (mintype.symbol().kind == CLASS) {
+ res[j] = mintype;
+ j = j + 1;
+ }
+ }
+ }
+ Type[] result = new Type[j];
+ System.arraycopy(res, 0, result, 0, j);
+ return result;
+ }
+
+ //todo: catch lubs not within bounds.
+ static Type arglub(Type[] types) {
+ Type pre = types[0].prefix();
+ Symbol sym = types[0].symbol();
+ Type[] args = new Type[sym.typeParams().length];
+ Type[][] argss = new Type[args.length][types.length];
+ for (int i = 0; i < types.length; i++) {
+ switch (types[i]) {
+ case TypeRef(Type pre1, Symbol sym1, Type[] args1):
+ assert sym == sym1;
+ assert args1.length == args.length;
+ if (!pre.isSameAs(pre1)) return NoType;
+ for (int j = 0; j < args1.length; j++)
+ argss[j][i] = args1[j];
+ case ErrorType:
+ return ErrorType;
+ default:
+ assert false : types[i];
+ }
+ }
+ for (int j = 0; j < args.length; j++) {
+ args[j] = commonType(argss[j]);
+ if (args[j] == NoType)
+ args[j] = CovarType(lub(argss[j]));
+ }
+ return TypeRef(pre, sym, args);
+ }
+
+ /** The frontier of a closure C is the minimal set of types such that
+ * the union of the closures of these types equals C.
+ */
+ static private Type[] frontier(Type[] closure) {
+ Type[] front = new Type[closure.length];
+ int j = 0;
+ for (int i = 0; i < closure.length; i++) {
+ int k = 0;
+ Type tp = closure[i];
+ while (k < j && !front[k].symbol().isSubClass(tp.symbol()))
+ k++;
+ if (k == j) {
+ front[j] = tp;
+ j++;
+ }
+ }
+ Type[] result = new Type[j];
+ System.arraycopy(front, 0, result, 0, j);
+ return result;
+ }
+
+ /** Return the least upper bound of non-empty array of types `tps'.
+ * todo: do we need to consider refinements as well?
+ */
+ public static Type lub(Type[] tps) {
+ //System.out.println("lub" + ArrayApply.toString(tps));//DEBUG
+ Type lubType = commonType(tps);
+ if (lubType != NoType) return lubType;
+ Type[][] closures = new Type[tps.length][];
+ for (int i = 0; i < tps.length; i++) {
+ if (!tps[i].isObjectType()) return Type.NoType;//todo: change
+ closures[i] = tps[i].closure();
+ }
+ Type[] allBaseTypes = intersection(closures);
+ Type[] leastBaseTypes = frontier(allBaseTypes);
+ if (leastBaseTypes.length == 0) return Type.NoType;
+ Scope members = new Scope();
+ lubType = compoundType(leastBaseTypes, members);
+ Type lubThisType = lubType.narrow();
+ //System.out.println("lubtype = " + lubType);//DEBUG
+
+ Symbol[] rsyms = new Symbol[tps.length];
+ Type[] rtps = new Type[tps.length];
+ for (int i = 0; i < allBaseTypes.length; i++) {
+ for (Scope.Entry e = allBaseTypes[i].members().elems;
+ e != Scope.Entry.NONE;
+ e = e.next) {
+ Name name = e.sym.name;
+ if ((e.sym.flags & PRIVATE) == 0 && lubType.lookup(name) == e.sym) {
+ Type symType = lubThisType.memberInfo(e.sym);
+ int j = 0;
+ while (j < tps.length) {
+ rsyms[j] = tps[j].lookupNonPrivate(name);
+ if (rsyms[j] == e.sym) break;
+ rtps[j] = tps[j].memberType(rsyms[j])
+ .substThis(tps[j].symbol(), lubThisType);
+ if (rtps[j].isSameAs(symType)) break;
+ j++;
+ }
+ if (j == tps.length) {
+ Symbol lubSym = lub(rsyms, rtps, lubType.symbol());
+ if (lubSym.kind != NONE && !lubSym.info().isSameAs(symType))
+ members.enter(lubSym);
+ }
+ }
+ }
+ }
+ //System.out.print("lub "); System.out.print(ArrayApply.toString(tps)); System.out.println(" = " + lubType);//DEBUG
+ if (leastBaseTypes.length == 1 && members.elems == Scope.Entry.NONE)
+ return leastBaseTypes[0];
+ else return lubType;
+ }
+
+ private static Type commonType(Type[] tps) {
+ Type tp = tps[0];
+ if (tp.isSameAsAll(tps)) return tp;
+ tp = tp.widen();
+ if (tp.isSameAsAll(widen(tps))) return tp;
+ return NoType;
+ }
+
+ private static Symbol lub(Symbol[] syms, Type[] tps, Symbol owner) {
+ //System.out.println("lub" + ArrayApply.toString(syms));//DEBUG
+ int lubKind = syms[0].kind;
+ for (int i = 1; i < syms.length; i++) {
+ Symbol sym = syms[i];
+ if (sym.kind == ERROR) return Symbol.NONE;
+ if (sym.isType() && sym.kind != lubKind) lubKind = TYPE;
+ }
+ if (lubKind == syms[0].kind && tps[0].isSameAsAll(tps)) {
+ return syms[0].cloneSymbol();
+ }
+ Type lubType = lub(tps);
+ if (lubType == Type.NoType) return Symbol.NONE;
+ Symbol lubSym;
+ switch (lubKind) {
+ case VAL:
+ lubSym = new TermSymbol(syms[0].pos, syms[0].name, owner, 0);
+ break;
+ case TYPE: case ALIAS: case CLASS:
+ lubSym = new TypeSymbol(TYPE, syms[0].pos, syms[0].name, owner, 0);
+ break;
+ default:
+ throw new ApplicationError();
+ }
+ lubSym.setInfo(lubType);
+ return lubSym;
+ }
+
+// Erasure --------------------------------------------------------------------------
+
+ public static Map erasureMap = new Map() {
+ public Type apply(Type t) { return t.erasure(); }
+ };
+
+ private static final Type[] unboxedType =
+ new Type[LastUnboxedTag + 1 - FirstUnboxedTag];
+ private static final Type[] unboxedArrayType =
+ new Type[LastUnboxedTag + 1 - FirstUnboxedTag];
+ private static final Name[] unboxedName =
+ new Name[LastUnboxedTag + 1 - FirstUnboxedTag];
+ private static final Name[] boxedName =
+ new Name[LastUnboxedTag + 1 - FirstUnboxedTag];
+ private static final Name[] boxedFullName =
+ new Name[LastUnboxedTag + 1 - FirstUnboxedTag];
+
+ private static void mkStdClassType(int kind, String unboxedstr, String boxedstr) {
+ unboxedType[kind - FirstUnboxedTag] = UnboxedType(kind);
+ unboxedArrayType[kind - FirstUnboxedTag] = UnboxedArrayType(unboxedType(kind));
+ unboxedName[kind - FirstUnboxedTag] = Name.fromString(unboxedstr);
+ boxedName[kind - FirstUnboxedTag] = Name.fromString(boxedstr);
+ boxedFullName[kind - FirstUnboxedTag] = Name.fromString("scala." + boxedstr);
+ }
+
+ static {
+ mkStdClassType(BYTE, "byte", "Byte");
+ mkStdClassType(SHORT, "short", "Short");
+ mkStdClassType(CHAR, "char", "Char");
+ mkStdClassType(INT, "int", "Int");
+ mkStdClassType(LONG, "long", "Long");
+ mkStdClassType(FLOAT, "float", "Float");
+ mkStdClassType(DOUBLE, "double", "Double");
+ mkStdClassType(BOOLEAN, "boolean", "Boolean");
+ mkStdClassType(UNIT, "void", "Unit");
+ }
+
+ /** Return unboxed type of given kind.
+ */
+ public static Type unboxedType(int kind) {
+ return unboxedType[kind - FirstUnboxedTag];
+ }
+
+ /** Return unboxed array type of given element kind.
+ */
+ public static Type unboxedArrayType(int kind) {
+ return unboxedArrayType[kind - FirstUnboxedTag];
+ }
+
+ /** Return the name of unboxed type of given kind.
+ */
+ public static Name unboxedName(int kind) {
+ return unboxedName[kind - FirstUnboxedTag];
+ }
+
+ /** Return the name of boxed type of given kind.
+ */
+ public static Name boxedName(int kind) {
+ return boxedName[kind - FirstUnboxedTag];
+ }
+
+ /** Return the full name of boxed type of given kind.
+ */
+ public static Name boxedFullName(int kind) {
+ return boxedFullName[kind - FirstUnboxedTag];
+ }
+
+ /** If type is boxed, return its unboxed equivalent; otherwise return the type
+ * itself.
+ */
+ public Type unbox() {
+ switch (this) {
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ if ((sym.flags & MODUL) == 0) {
+ Name fullname = sym.fullName();
+ if (fullname == Names.scala_Array && args.length == 1
+ /*&& args[0].unalias().symbol().kind != TYPE Q: why needed?*/) {
+ return UnboxedArrayType(args[0].erasure());
+ } else {
+ for (int i = 0; i < boxedFullName.length; i++) {
+ if (boxedFullName[i] == fullname) return unboxedType[i];
+ }
+ }
+ }
+ }
+ return this;
+ }
+
+ /** Return the erasure of this type.
+ */
+ public Type erasure() {
+ switch (this) {
+ case ThisType(_):
+ case SingleType(_, _):
+ return widen().erasure();
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ switch (sym.kind) {
+ case ALIAS: case TYPE:
+ return pre.memberInfo(sym).erasure();
+
+ case CLASS:
+ if (sym.fullName() == Names.java_lang_Object ||
+ sym.fullName() == Names.scala_AnyRef ||
+ sym.fullName() == Names.scala_AnyVal)
+ return Global.instance.definitions.ANY_TYPE;
+ else {
+ Type this1 = unbox();
+ if (this1 != this) return this1;
+ else if (args.length == 0) return this;
+ else return TypeRef(pre, sym, Type.EMPTY_ARRAY);
+ }
+
+ default: throw new ApplicationError();
+ }
+ case CompoundType(Type[] parents, _):
+ if (parents.length > 0) return parents[0].erasure();
+ else return this;
+ case CovarType(Type tp):
+ return tp.erasure(); // note: needed because of UnboxedArrayType
+ case MethodType(Symbol[] params, Type tp):
+ Symbol[] params1 = erasureMap.map(params);
+ Type tp1 = tp.erasure();
+ switch (tp1) {
+ case MethodType(Symbol[] params2, Type tp2):
+ Symbol[] newparams = new Symbol[params1.length + params2.length];
+ System.arraycopy(params1, 0, newparams, 0, params1.length);
+ System.arraycopy(params2, 0, newparams, params1.length, params2.length);
+ return MethodType(newparams, tp2);
+ default:
+ if (params1 == params && tp1 == tp) return this;
+ else return MethodType(params1, tp1);
+ }
+ case PolyType(_, Type result):
+ return result.erasure();
+ default:
+ return erasureMap.map(this);
+ }
+ }
+
+// Object Interface -----------------------------------------------------------------
+
+ public String toString() {
+ switch (this) {
+ case ErrorType:
+ return "<error>";
+ case AnyType:
+ return "<any type>";
+ case NoType:
+ return "<notype>";
+ case ThisType(Symbol sym):
+ if (sym.isRoot()) return "<root>.this.type";
+ else if (this == localThisType) return "<local>.this.type";
+ else {
+ Type this1 = (Global.instance.debug) ? this : expandModuleThis();
+ if (this1 == this) return sym.nameString() + ".this.type";
+ else return this1.toString();
+ }
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ if (sym.isRoot()) return "<root>";
+ if (!Global.instance.debug) {
+ if (isTupleType())
+ return ArrayApply.toString(
+ dropVarianceMap.map(args), "[", ",", "]");
+ if (isFunctionType()) {
+ Type[] params = new Type[args.length - 1];
+ System.arraycopy(args, 0, params, 0, params.length);
+ return ArrayApply.toString(params, "(", ",", ") => ") +
+ args[params.length].dropVariance();
+ }
+ }
+ Type pre1 = (Global.instance.debug) ? pre : pre.expandModuleThis();
+ String result = pre1.prefixString() + sym.nameString() + sym.idString();
+ if (args.length != 0)
+ result = result + ArrayApply.toString(args, "[", ",", "]");
+ return result;
+ case SingleType(Type pre, Symbol sym):
+ if ((sym.flags & SYNTHETIC) != 0 && !Global.instance.debug)
+ return widen().toString();
+ if (sym.isRoot()) return "<root>.type";
+ Type pre1 = (Global.instance.debug) ? pre : pre.expandModuleThis();
+ return pre1.prefixString() + sym.nameString() + sym.idString() + ".type";
+ case CompoundType(Type[] parts, Scope members):
+ validate();//debug
+ StringBuffer buf = new StringBuffer();
+ if (parts.length > 0) {
+ buf.append(parts[0].toString());
+ int i = 1;
+ while (i < parts.length) {
+ buf.append(" with ");
+ buf.append(parts[i].toString());
+ i++;
+ }
+ }
+ boolean first = true;
+ for (Scope.SymbolIterator it = members.iterator(); it.hasNext(); ) {
+ Symbol sym = it.next();
+ buf.append(first ? "{" : ", ");
+ first = false;
+ buf.append(sym.defString());
+ }
+ if (!first) buf.append("}");
+ return buf.toString();
+ case MethodType(Symbol[] vparams, Type result):
+ return ArrayApply.toString(Symbol.type(vparams), "(", ",", ")") + result;
+ case PolyType(Symbol[] tparams, Type result):
+ return ArrayApply.toString(Symbol.defString(tparams), "[", ",", "]") +
+ result;
+ case CovarType(Type tp):
+ return "+" + tp;
+ case OverloadedType(Symbol[] alts, Type[] alttypes):
+ return "<overloaded> " + ArrayApply.toString(alttypes, "", " <and> ", "");//debug
+ case TypeVar(Type origin, Constraint constr):
+ if (constr.inst != NoType) return constr.inst.toString();
+ else return origin + "?";
+ case UnboxedType(int kind):
+ return unboxedName(kind).toString();
+ case UnboxedArrayType(Type elemtp):
+ return elemtp.toString() + "[]";
+ case LazyType():
+ return "<lazy type " + getClass() + ">";
+ default:
+ return "<unknown type " + getClass() + ">";
+ }
+ }
+
+ public String toLongString() {
+ String str = toString();
+ if (str.endsWith(".type")) return str + " (with underlying type " + widen() + ")";
+ else return str;
+ }
+
+ private String prefixString() {
+ if ((this == localThisType || symbol().isRoot()) && !Global.instance.debug) {
+ return "";
+ } else {
+ String spre = toString();
+ if (spre.length() == 0)
+ return "";
+ else if (spre.endsWith(".type"))
+ return spre.substring(0, spre.length() - 4);
+ else
+ return spre + "@";
+ }
+ }
+
+ public int hashCode() {
+ switch (this) {
+ case ErrorType:
+ return ERROR;
+ case NoType:
+ return NOtpe;
+ case ThisType(Symbol sym):
+ return THIStpe
+ ^ (sym.hashCode() * 41);
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ return NAMEDtpe
+ ^ (pre.hashCode() * 41)
+ ^ (sym.hashCode() * (41*41))
+ ^ (hashCode(args) * (41*41*41));
+ case SingleType(Type pre, Symbol sym):
+ return SINGLEtpe
+ ^ (pre.hashCode() * 41)
+ ^ (sym.hashCode() * (41*41));
+ case CompoundType(Type[] parts, Scope members):
+ return COMPOUNDtpe
+ ^ (hashCode(parts) * 41)
+ ^ (members.hashCode() * (41 * 41));
+ case MethodType(Symbol[] vparams, Type result):
+ return METHODtpe
+ ^ (hashCode(Symbol.type(vparams)) * 41)
+ ^ (result.hashCode() * (41 * 41));
+ case PolyType(Symbol[] tparams, Type result):
+ return POLYtpe
+ ^ (hashCode(tparams) * 41)
+ ^ (result.hashCode() * (41 * 41));
+ case CovarType(Type tp):
+ return COVARtpe
+ ^ (tp.hashCode() * (41));
+ case OverloadedType(Symbol[] alts, Type[] alttypes):
+ return OVERLOADEDtpe
+ ^ (hashCode(alts) * 41)
+ ^ (hashCode(alttypes) * (41 * 41));
+ case UnboxedType(int kind):
+ return UNBOXEDtpe
+ ^ (kind * 41);
+ case UnboxedArrayType(Type elemtp):
+ return UNBOXEDARRAYtpe
+ ^ (elemtp.hashCode() * 41);
+ default:
+ throw new ApplicationError();
+ }
+ }
+
+ public static int hashCode(Object[] elems) {
+ int h = 0;
+ for (int i = 0; i < elems.length; i++)
+ h = h * 41 + elems[i].hashCode();
+ return h;
+ }
+
+ public static int hashCode(Scope.Entry elems) {
+ int h = 0;
+ for (Scope.Entry e = elems; e != Scope.Entry.NONE; e = e.next)
+ h = h * 41
+ + e.sym.kind
+ + e.sym.name.hashCode()
+ + e.sym.info().hashCode();
+ return h;
+ }
+
+ // todo: change in relation to needs.
+
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ } else if (other instanceof Type) {
+ Type that = (Type) other;
+ switch (this) {
+ case ErrorType:
+ return that == ErrorType;
+ case NoType:
+ return that == NoType;
+ case ThisType(Symbol sym):
+ switch (that) {
+ case ThisType(Symbol sym1):
+ return sym == sym1;
+ default: return false;
+ }
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ switch (that) {
+ case TypeRef(Type pre1, Symbol sym1, Type[] args1):
+ return pre.equals(pre1) && sym == sym1 && equals(args, args1);
+ default: return false;
+ }
+ case SingleType(Type pre, Symbol sym):
+ switch (that) {
+ case SingleType(Type pre1, Symbol sym1):
+ return pre.equals(pre1) && sym == sym1;
+ default: return false;
+ }
+ case CompoundType(Type[] parts, Scope members):
+ switch (that) {
+ case CompoundType(Type[] parts1, Scope members1):
+ return parts.equals(parts1) && members.equals(members1);
+ default: return false;
+ }
+ case MethodType(Symbol[] vparams, Type result):
+ switch (that) {
+ case MethodType(Symbol[] vparams1, Type result1):
+ return equals(Symbol.type(vparams), Symbol.type(vparams1)) &&
+ result.equals(result1);
+ default: return false;
+ }
+ case PolyType(Symbol[] tparams, Type result):
+ switch (that) {
+ case PolyType(Symbol[] tparams1, Type result1):
+ return equals(tparams, tparams1) && result.equals(result1);
+ default: return false;
+ }
+ case CovarType(Type tp):
+ switch (that) {
+ case CovarType(Type tp1):
+ return tp.equals(tp1);
+ default: return false;
+ }
+ case OverloadedType(Symbol[] alts, Type[] alttypes):
+ switch (that) {
+ case OverloadedType(Symbol[] alts1, Type[] alttypes1):
+ return equals(alts, alts1) && equals(alttypes, alttypes1);
+ default: return false;
+ }
+ case UnboxedType(int kind):
+ switch (that) {
+ case UnboxedType(int kind1):
+ return kind == kind1;
+ default: return false;
+ }
+ case UnboxedArrayType(Type elemtp):
+ switch (that) {
+ case UnboxedArrayType(Type elemtp1):
+ return elemtp.equals(elemtp1);
+ default: return false;
+ }
+ default:
+ }
+ }
+ return false;
+ }
+
+ public static boolean equals(Object[] elems1, Object[] elems2) {
+ if (elems1.length != elems2.length) return false;
+ for (int i = 0; i < elems1.length; i++) {
+ if (!elems1[i].equals(elems2[i])) return false;
+ }
+ return true;
+ }
+
+// Type.List class -----------------------------------------------------------------
+
+ /** A class for lists of types.
+ */
+ public static class List {
+ public Type head;
+ public List tail;
+ public List(Type head, List tail) {
+ this.head = head; this.tail = tail;
+ }
+ public int length() {
+ return (this == EMPTY) ? 0 : 1 + tail.length();
+ }
+ public Type[] toArray() {
+ Type[] ts = new Type[length()];
+ copyToArray(ts, 0, 1);
+ return ts;
+ }
+ public void copyToArray(Type[] ts, int start, int delta) {
+ if (this != EMPTY) {
+ ts[start] = head;
+ tail.copyToArray(ts, start+delta, delta);
+ }
+ }
+ public Type[] toArrayReverse() {
+ Type[] ts = new Type[length()];
+ copyToArray(ts, ts.length - 1, -1);
+ return ts;
+ }
+
+ public static List EMPTY = new List(null, null);
+
+ public static List append(List l, Type tp) {
+ return (l == EMPTY) ? new List(tp, EMPTY)
+ : new List(l.head, append(l.tail, tp));
+ }
+ }
+
+// Type.Constraint class -------------------------------------------------------
+
+ /** A class for keeping sub/supertype constraints and instantiations
+ * of type variables.
+ */
+ public static class Constraint {
+ public List lobounds = List.EMPTY;
+ public List hibounds = List.EMPTY;
+ public Type inst = NoType;
+
+ public boolean instantiate(Type tp) {
+ for (List l = lobounds; l != List.EMPTY; l = l.tail) {
+ if (!l.head.isSubType(tp)) return false;
+ }
+ for (List l = hibounds; l != List.EMPTY; l = l.tail) {
+ if (!tp.isSubType(l.head)) return false;
+ }
+ inst = tp;
+ return true;
+ }
+ }
+
+// Type.Error class --------------------------------------------------------------
+
+ /** A class for throwing type errors
+ */
+ public static class Error extends java.lang.Error {
+ public String msg;
+ public Error(String msg) {
+ super(msg);
+ this.msg = msg;
+ }
+ }
+
+ /** A class for throwing type errors
+ */
+ public static class VarianceError extends Error {
+ public VarianceError(String msg) {
+ super(msg);
+ }
+ }
+}
+
+/* A standard pattern match:
+
+ case ErrorType:
+ case AnyType:
+ case NoType:
+ case ThisType(Symbol sym):
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ case SingleType(Type pre, Symbol sym):
+ case CompoundType(Type[] parts, Scope members):
+ case MethodType(Symbol[] vparams, Type result):
+ case PolyType(Symbol[] tparams, Type result):
+ case OverloadedType(Symbol[] alts, Type[] alttypes):
+ case CovarType(Type tp):
+*/
+
diff --git a/sources/scalac/symtab/TypeTags.java b/sources/scalac/symtab/TypeTags.java
new file mode 100644
index 0000000000..a3bd103432
--- /dev/null
+++ b/sources/scalac/symtab/TypeTags.java
@@ -0,0 +1,47 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab;
+
+public interface TypeTags {
+
+ /** unboxed type tags
+ */
+ int BYTE = 10;
+ int CHAR = 11;
+ int SHORT = 12;
+ int INT = 13;
+ int LONG = 14;
+ int FLOAT = 15;
+ int DOUBLE = 16;
+ int BOOLEAN = 17;
+ int UNIT = 18;
+ int STRING = 19;
+
+ int FirstUnboxedTag = BYTE;
+ int LastUnboxedTag = UNIT;
+
+ /** other type tags (used for hashcodes and Pickling)
+ */
+ int ERRORtpe = 20;
+ int NOtpe = 21;
+ int THIStpe = 22;
+ int NAMEDtpe = 23;
+ int SINGLEtpe = 24;
+ int COMPOUNDtpe = 25;
+ int METHODtpe = 26;
+ int POLYtpe = 27;
+ int CONSTRUCTORtpe = 28;
+ int COVARtpe = 29;
+ int OVERLOADEDtpe = 30;
+ int UNBOXEDtpe = 31;
+ int UNBOXEDARRAYtpe = 32;
+
+ int firstTypeTag = ERRORtpe;
+ int lastTypeTag = UNBOXEDARRAYtpe;
+}
diff --git a/sources/scalac/symtab/classfile/AttributeParser.java b/sources/scalac/symtab/classfile/AttributeParser.java
new file mode 100644
index 0000000000..0ed09b44d0
--- /dev/null
+++ b/sources/scalac/symtab/classfile/AttributeParser.java
@@ -0,0 +1,439 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab.classfile;
+
+import scalac.*;
+import scalac.symtab.*;
+import scalac.util.*;
+import java.util.*;
+
+public class AttributeParser implements ClassfileConstants {
+
+ /** the classfile input buffer
+ */
+ protected AbstractFileReader in;
+
+ /** the constant pool
+ */
+ protected ConstantPool pool;
+
+ protected ClassfileParser parser;
+
+ /** constructor
+ */
+ public AttributeParser(AbstractFileReader in, ConstantPool pool, ClassfileParser parser) {
+ this.in = in;
+ this.pool = pool;
+ this.parser = parser;
+ }
+
+ public int nameToId(Name name) {
+ if (name == SOURCEFILE_N)
+ return SOURCEFILE_ATTR;
+ if (name == SYNTHETIC_N)
+ return SYNTHETIC_ATTR;
+ if (name == DEPRECATED_N)
+ return DEPRECATED_ATTR;
+ if (name == CODE_N)
+ return CODE_ATTR;
+ if (name == EXCEPTIONS_N)
+ return EXCEPTIONS_ATTR;
+ if (name == CONSTANT_VALUE_N)
+ return CONSTANT_VALUE_ATTR;
+ if (name == LINE_NUM_TABLE_N)
+ return LINE_NUM_TABLE_ATTR;
+ if (name == LOCAL_VAR_TABLE_N)
+ return LOCAL_VAR_TABLE_ATTR;
+ if (name == INNERCLASSES_N)
+ return INNERCLASSES_ATTR;
+ if (name == META_N)
+ return META_ATTR;
+ if (name == SCALA_N)
+ return SCALA_ATTR;
+ return BAD_ATTR;
+ }
+
+ public Symbol readAttributes(Symbol def, Type type, int attrs) {
+ char nattr = in.nextChar();
+ for (int i = 0; i < nattr; i++) {
+ Name attrName = (Name)pool.readPool(in.nextChar());
+ int attr = nameToId(attrName);
+ int attrLen = in.nextInt();
+ if ((attrs & attr) == 0) {
+ //System.out.println("# skipping " + attrName + " of " + def);
+ in.skip(attrLen);
+ } else {
+ //System.out.println("# reading " + attrName + " of " + def);
+ readAttribute(def, type, attr, attrLen);
+ }
+ }
+ return def;
+ }
+
+ public void readAttribute(Symbol sym, Type type, int attr, int attrLen) {
+ switch (attr) {
+ // class attributes
+ case SCALA_ATTR:
+ in.skip(attrLen);
+ /* not yet
+ Name sourcefile = (Name)pool.readPool(in.nextChar());
+ new UnPickle(
+ (JavaClassSymbol) sym, in.nextBytes(attrLen - 2), sourcefile);
+ */
+ return;
+
+ case SOURCEFILE_ATTR:
+ // ((ClassDef)def).sourcefile = (Name)reader.readPool(in.nextChar());
+ in.skip(attrLen);
+ return;
+
+ case INNERCLASSES_ATTR:
+ /* int n = in.nextChar();
+ for (int i = 0; i < n; i++) {
+ Symbol inner = (Symbol)pool.readPool(in.nextChar());
+ Symbol outer = (Symbol)pool.readPool(in.nextChar());
+ Name name = (Name)pool.readPool(in.nextChar());
+ int flags = in.nextChar();
+ if (name != null) {
+ inner.owner(outer);
+ inner.mangled(name);
+ inner.flags = flags;
+ }
+ } */
+ in.skip(attrLen);
+ return;
+
+ // method attributes
+ case CODE_ATTR:
+ in.skip(attrLen);
+ return;
+
+ case EXCEPTIONS_ATTR:
+ //int nexceptions = in.nextChar();
+ //Type[] thrown = new Type[nexceptions];
+ //for (int j = 0; j < nexceptions; j++)
+ // thrown[j] = make.classType(reader.readClassName(in.nextChar()));
+ //((MethodType)def.type).thrown = thrown;
+ in.skip(attrLen);
+ return;
+
+ case LINE_NUM_TABLE_ATTR:
+ in.skip(attrLen);
+ return;
+
+ case LOCAL_VAR_TABLE_ATTR:
+ in.skip(attrLen);
+ return;
+
+ // general attributes
+ case SYNTHETIC_ATTR:
+ sym.flags |= Modifiers.SYNTHETIC;
+ return;
+
+ case DEPRECATED_ATTR:
+ sym.flags |= Modifiers.DEPRECATED;
+ return;
+
+ case CONSTANT_VALUE_ATTR:
+ // Type ctype = (Type)reader.readPool(in.nextChar());
+ // def.type = types.coerce(ctype, def.type);
+ in.skip(attrLen);
+ return;
+
+ case META_ATTR:
+ //System.out.println("parsing meta data for " + sym);
+ String meta = pool.readPool(in.nextChar()).toString().trim();
+ sym.setInfo(new MetaParser(meta, tvars, sym, type).parse(), parser.phaseId);
+
+ return;
+ }
+ throw new RuntimeException("unknown classfile attribute");
+ }
+
+ Scope tvars = new Scope();
+
+ class MetaParser {
+
+ Symbol owner;
+ StringTokenizer scanner;
+ Type defaultType;
+ String token;
+ Scope tvars;
+ Scope locals;
+
+ MetaParser(String meta, Scope tvars, Symbol owner, Type defaultType) {
+ //System.out.println("meta = " + meta);
+ this.scanner = new StringTokenizer(meta, "()[], \t<;", true);
+ this.defaultType = defaultType;
+ this.owner = owner;
+ this.tvars = tvars;
+ }
+
+ private Symbol getTVar(String name) {
+ return getTVar(name, parser.c.constructor());
+ }
+
+ private Symbol getTVar(String name, Symbol owner) {
+ if (name.startsWith("?")) {
+ if (locals != null) {
+ Symbol s = locals.lookup(Name.fromString(name).toTypeName());
+ if (s != Symbol.NONE)
+ return s;
+ }
+ Symbol s = tvars.lookup(Name.fromString(name).toTypeName());
+ if (s == Symbol.NONE) {
+ s = new TypeSymbol(Kinds.TYPE,
+ Position.NOPOS,
+ Name.fromString(token).toTypeName(),
+ owner,
+ Modifiers.PARAM);
+ s.setInfo(parser.defs.ANY_TYPE, parser.phaseId);
+ tvars.enter(s);
+ }
+ return s;
+ } else
+ return Symbol.NONE;
+ }
+
+ private String nextToken() {
+ do {
+ token = scanner.nextToken().trim();
+ } while (token.length() == 0);
+ return token;
+ }
+
+ protected Type parse() {
+ if (scanner.hasMoreTokens()) {
+ nextToken();
+ if (!scanner.hasMoreTokens())
+ return defaultType;
+ if ("class".equals(token))
+ return parseMetaClass();
+ if ("method".equals(token))
+ return parseMetaMethod();
+ if ("field".equals(token))
+ return parseMetaField();
+ if ("constr".equals(token))
+ return parseConstrField();
+ }
+ return defaultType;
+ }
+
+ protected Type parseMetaClass() {
+ nextToken();
+ //System.out.println("parse meta class " + token);//DEBUG
+ if ("[".equals(token)) {
+ try {
+ Vector syms = new Vector();
+ do {
+ nextToken();
+ assert token.startsWith("?");
+ Symbol s = getTVar(token);
+ if (s == Symbol.NONE)
+ return defaultType;
+ nextToken();
+ //System.out.println("new var " + s + ", " + token);//DEBUG
+ if (token.equals("<")) {
+ nextToken();
+ s.setInfo(parseType(), parser.phaseId);
+ }
+ syms.add(s);
+ } while (token.equals(","));
+ assert "]".equals(token);
+ nextToken();
+ Symbol[] smbls = (Symbol[])syms.toArray(new Symbol[syms.size()]);
+ //System.out.println("*** " + syms);//DEBUG
+ Type constrtype = Type.appliedType(
+ parser.ctype, Symbol.type(smbls));
+
+ if ((parser.c.flags & Modifiers.INTERFACE) != 0) {
+ parser.c.constructor().setInfo(
+ Type.PolyType(smbls, constrtype), parser.phaseId);
+ //System.out.println("info = " + parser.c.constructor().info());//DEBUG
+ }
+ Symbol[] constrs;
+ switch (parser.c.constructor().rawInfo()) {
+ case OverloadedType(Symbol[] alts, _):
+ constrs = alts;
+ break;
+ default:
+ constrs = new Symbol[]{parser.c.constructor()};
+ }
+ for (int i = 0; i < constrs.length; i++) {
+ //System.out.println("info = " + e.sym.info());
+ switch (constrs[i].rawInfo()) {
+ case MethodType(Symbol[] vparams, _):
+ constrs[i].setInfo(
+ Type.PolyType(smbls,
+ Type.MethodType(
+ vparams, constrtype)), parser.phaseId);
+ break;
+ case PolyType(_, _):
+ constrs[i].setInfo(
+ Type.PolyType(smbls, constrtype), parser.phaseId);
+ break;
+ }
+ //System.out.println("*** constructor " + e.sym + ": " + e.sym.info());//DEBUG
+ }
+ } catch (NoSuchElementException e) {
+ }
+ }
+ Type res = defaultType;
+ if ("extends".equals(token)) {
+ Vector basetpes = new Vector();
+ do {
+ nextToken();
+ basetpes.add(parseType());
+ } while (token.equals("with"));
+ switch (defaultType) {
+ case CompoundType(_, Scope scope):
+ res = Type.compoundType(
+ (Type[])basetpes.toArray(new Type[basetpes.size()]),
+ scope,
+ defaultType.symbol());
+ }
+ }
+ assert ";".equals(token);
+ return res;
+ }
+
+ protected Type parseType() {
+ String name = token;
+ Symbol s = getTVar(name);
+ nextToken();
+ if (s != Symbol.NONE)
+ return s.type();
+ Symbol clazz = parser.defs.getClass(Name.fromString(name));
+ if (token.equals("[")) {
+ Vector types = new Vector();
+ do {
+ nextToken();
+ types.add(parseType());
+ } while (token.equals(","));
+ assert "]".equals(token);
+ nextToken();
+ Type[] args = new Type[types.size()];
+ types.toArray(args);
+ return Type.TypeRef(clazz.owner().thisType(), clazz, args);
+ } else {
+ return parser.defs.monoType(clazz);
+ }
+ }
+
+ protected Type parseMetaMethod() {
+ locals = new Scope();
+ try {
+ nextToken();
+ Symbol[] smbls = null;
+ //System.out.println("parse meta method " + token);
+ if ("[".equals(token)) {
+ Vector syms = new Vector();
+ do {
+ nextToken();
+ if ("]".equals(token))
+ break;
+ assert token.startsWith("?");
+ Symbol s = getTVar(token, owner);
+ if (s == Symbol.NONE)
+ return defaultType;
+ nextToken();
+ //System.out.println("new var " + s + ", " + token);
+ if (token.equals("<")) {
+ nextToken();
+ s.setInfo(parseType(), parser.phaseId);
+ }
+ syms.add(s);
+ } while (token.equals(","));
+ assert "]".equals(token);
+ nextToken();
+ smbls = (Symbol[])syms.toArray(new Symbol[syms.size()]);
+ }
+ if ("(".equals(token)) {
+ int i = 0;
+ Vector params = new Vector();
+ do {
+ nextToken();
+ if (")".equals(token))
+ break;
+ params.add(new TermSymbol(
+ Position.NOPOS,
+ Name.fromString("x" + (i++)),
+ owner,
+ Modifiers.PARAM).setInfo(parseType(), parser.phaseId));
+ //System.out.println(" + " + token);
+ } while (token.equals(","));
+ assert ")".equals(token);
+ nextToken();
+ //System.out.println("+++ method " + token);
+ Type restpe = parseType();
+ assert ";".equals(token);
+ if (smbls == null)
+ return Type.MethodType(
+ (Symbol[])params.toArray(new Symbol[params.size()]),
+ restpe);
+ else
+ return Type.PolyType(
+ smbls,
+ Type.MethodType(
+ (Symbol[])params.toArray(new Symbol[params.size()]),
+ restpe));
+ } else {
+ Type res = parseType();
+ assert ";".equals(token);
+ if (smbls == null)
+ return Type.PolyType(Symbol.EMPTY_ARRAY, res);
+ else
+ return Type.PolyType(smbls, res);
+ }
+ } catch (NoSuchElementException e) {
+ return defaultType;
+ } finally {
+ locals = null;
+ }
+ }
+
+ protected Type parseMetaField() {
+ nextToken();
+ return parseType();
+ }
+
+ protected Type parseConstrField() {
+ try {
+ nextToken();
+ //System.out.println("+++ constr " + token);
+ if ("(".equals(token)) {
+ int i = 0;
+ Vector params = new Vector();
+ do {
+ nextToken();
+ if (")".equals(token))
+ break;
+ params.add(new TermSymbol(
+ Position.NOPOS,
+ Name.fromString("x" + (i++)),
+ owner,
+ Modifiers.PARAM).setInfo(parseType(), parser.phaseId));
+ //System.out.println(" + " + token);
+ } while (token.equals(","));
+ assert ")".equals(token);
+ nextToken();
+ assert ";".equals(token);
+ return Type.MethodType(
+ (Symbol[])params.toArray(new Symbol[params.size()]),
+ parser.ctype);
+ } else {
+ assert ";".equals(token);
+ return Type.PolyType(Symbol.EMPTY_ARRAY, parser.ctype);
+ }
+ } catch (NoSuchElementException e) {
+ return defaultType;
+ }
+ }
+ }
+}
diff --git a/sources/scalac/symtab/classfile/ClassParser.java b/sources/scalac/symtab/classfile/ClassParser.java
new file mode 100644
index 0000000000..9948ba33cf
--- /dev/null
+++ b/sources/scalac/symtab/classfile/ClassParser.java
@@ -0,0 +1,111 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab.classfile;
+
+import scalac.*;
+import scalac.symtab.*;
+import scalac.util.*;
+import java.io.*;
+
+
+public class ClassParser extends Type.LazyType {
+
+ /** the global compilation environment
+ */
+ protected Global global;
+
+ public ClassParser(Global global) {
+ this.global = global;
+ }
+
+ /** complete class symbol c by loading the class
+ */
+ public void complete(Symbol c) {
+ //System.out.println("loading " + c);//DEBUG
+ try {
+ long msec = System.currentTimeMillis();
+ String filename = externalizeFileName(c.fullName()) + ".class";
+ AbstractFile f = global.classPath.openFile(filename);
+ if (f == null)
+ global.error("could not read class " + c);
+ else {
+ new ClassfileParser(global, new AbstractFileReader(f), c).parse();
+ global.operation("loaded " + f.getPath() + " in " +
+ (System.currentTimeMillis() - msec) + "ms");
+ //for (Definition e = c.locals().elems; e != null; e = e.sibling)
+ // if (e.def.kind == TYP)
+ // e.def.complete();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ global.error("i/o error while loading " + c);
+ c.setInfo(Type.ErrorType);
+ }
+ }
+
+ /** return external representation of file name s,
+ * converting '.' to File.separatorChar
+ */
+ public String externalizeFileName(Name n) {
+ if ((n == null) || (n.length() == 0))
+ return ".";
+ byte[] ascii = n.toAscii();
+ String s = SourceRepresentation.ascii2string(
+ ascii, 0, ascii.length);
+ return s.replace('.', File.separatorChar);
+ }
+
+ public Type.LazyType staticsParser(Symbol clazz) {
+ return new StaticsParser(clazz);
+ }
+
+ public Type.LazyType aliasParser(Symbol alias) {
+ return new AliasParser(alias);
+ }
+
+ class StaticsParser extends Type.LazyType {
+ Symbol clazz;
+
+ StaticsParser(Symbol clazz) {
+ this.clazz = clazz;
+ }
+
+ public void complete(Symbol statics) {
+ ClassParser.this.complete(clazz);
+ }
+ }
+
+ class AliasParser extends Type.LazyType {
+ Symbol alias;
+
+ AliasParser(Symbol alias) {
+ this.alias = alias;
+ }
+
+ public void complete(Symbol c) {
+ try {
+ long msec = System.currentTimeMillis();
+ String filename = externalizeFileName(alias.fullName()) + ".class";
+ AbstractFile f = global.classPath.openFile(filename);
+ if (f == null)
+ global.error("could not read class " + c);
+ else {
+ new ClassfileParser(global, new AbstractFileReader(f), c).parse();
+ global.operation("loaded " + f.getPath() + " in " +
+ (System.currentTimeMillis() - msec) + "ms");
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ global.error("i/o error while loading " + c);
+ c.setInfo(Type.ErrorType);
+ }
+ }
+ }
+}
+
diff --git a/sources/scalac/symtab/classfile/ClassfileConstants.java b/sources/scalac/symtab/classfile/ClassfileConstants.java
new file mode 100644
index 0000000000..16b9f5af44
--- /dev/null
+++ b/sources/scalac/symtab/classfile/ClassfileConstants.java
@@ -0,0 +1,57 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab.classfile;
+
+import scalac.util.Name;
+
+public interface ClassfileConstants {
+
+ int JAVA_MAGIC = 0xCAFEBABE;
+ int JAVA_MAJOR_VERSION = 45;
+ int JAVA_MINOR_VERSION = 3;
+
+ int CONSTANT_UTF8 = 1;
+ int CONSTANT_UNICODE = 2;
+ int CONSTANT_INTEGER = 3;
+ int CONSTANT_FLOAT = 4;
+ int CONSTANT_LONG = 5;
+ int CONSTANT_DOUBLE = 6;
+ int CONSTANT_CLASS = 7;
+ int CONSTANT_STRING = 8;
+ int CONSTANT_FIELDREF = 9;
+ int CONSTANT_METHODREF = 10;
+ int CONSTANT_INTFMETHODREF = 11;
+ int CONSTANT_NAMEANDTYPE = 12;
+
+ int BAD_ATTR = 0x00000;
+ int SOURCEFILE_ATTR = 0x00001;
+ int SYNTHETIC_ATTR = 0x00002;
+ int DEPRECATED_ATTR = 0x00004;
+ int CODE_ATTR = 0x00008;
+ int EXCEPTIONS_ATTR = 0x00010;
+ int CONSTANT_VALUE_ATTR = 0x00020;
+ int LINE_NUM_TABLE_ATTR = 0x00040;
+ int LOCAL_VAR_TABLE_ATTR = 0x00080;
+ int INNERCLASSES_ATTR = 0x08000;
+ int META_ATTR = 0x10000;
+ int SCALA_ATTR = 0x20000;
+
+ Name SOURCEFILE_N = Name.fromString("SourceFile");
+ Name SYNTHETIC_N = Name.fromString("Synthetic");
+ Name DEPRECATED_N = Name.fromString("Deprecated");
+ Name CODE_N = Name.fromString("Code");
+ Name EXCEPTIONS_N = Name.fromString("Exceptions");
+ Name CONSTANT_VALUE_N = Name.fromString("ConstantValue");
+ Name LINE_NUM_TABLE_N = Name.fromString("LineNumberTable");
+ Name LOCAL_VAR_TABLE_N = Name.fromString("LocalVariableTable");
+ Name INNERCLASSES_N = Name.fromString("InnerClasses");
+ Name META_N = Name.fromString("JacoMeta");
+ Name SCALA_N = Name.fromString("ScalaSignature");
+ Name CONSTR_N = Name.fromString("<init>");
+}
diff --git a/sources/scalac/symtab/classfile/ClassfileParser.java b/sources/scalac/symtab/classfile/ClassfileParser.java
new file mode 100644
index 0000000000..956c83968f
--- /dev/null
+++ b/sources/scalac/symtab/classfile/ClassfileParser.java
@@ -0,0 +1,239 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab.classfile;
+
+import scalac.*;
+import scalac.util.*;
+import scalac.symtab.*;
+import java.io.*;
+import java.util.*;
+
+//todo: don't keep statics module in scope.
+
+public class ClassfileParser implements ClassfileConstants {
+
+ static final int CLASS_ATTR = SOURCEFILE_ATTR
+ | INNERCLASSES_ATTR
+ | SYNTHETIC_ATTR
+ | DEPRECATED_ATTR
+ | META_ATTR
+ | SCALA_ATTR;
+ static final int METH_ATTR = CODE_ATTR
+ | EXCEPTIONS_ATTR
+ | SYNTHETIC_ATTR
+ | DEPRECATED_ATTR
+ | META_ATTR;
+ static final int FIELD_ATTR = CONSTANT_VALUE_ATTR
+ | SYNTHETIC_ATTR
+ | DEPRECATED_ATTR
+ | META_ATTR;
+
+ protected Global global;
+ protected AbstractFileReader in;
+ protected Symbol c;
+ protected Type ctype;
+ protected Scope locals;
+ protected Scope statics;
+ protected Scope constr;
+ protected JavaTypeFactory make;
+ protected Signatures sigs;
+ protected ConstantPool pool;
+ protected AttributeParser attrib;
+ protected Definitions defs;
+ protected int phaseId;
+
+
+ public ClassfileParser(Global global, AbstractFileReader in, Symbol c) {
+ this.global = global;
+ this.in = in;
+ this.c = c;
+ this.ctype = Type.TypeRef(c.owner().thisType(), c, Type.EMPTY_ARRAY);
+ this.make = new JavaTypeCreator(global);
+ this.sigs = new Signatures(global, make);
+ this.pool = new ConstantPool(in, sigs);
+ this.attrib = new AttributeParser(in, pool, this);
+ this.defs = global.definitions;
+ this.phaseId = global.POST_ANALYZER_PHASE_ID;
+ }
+
+
+ /** parse the classfile and throw IO exception if there is an
+ * error in the classfile structure
+ */
+ public void parse() throws IOException {
+ try {
+ if (in.nextInt() != JAVA_MAGIC)
+ throw new IOException("illegal start of class file");
+ int minorVersion = in.nextChar();
+ int majorVersion = in.nextChar();
+ if ((majorVersion < JAVA_MAJOR_VERSION) ||
+ ((majorVersion == JAVA_MAJOR_VERSION) &&
+ (minorVersion < JAVA_MINOR_VERSION)))
+ throw new IOException("class file has wrong version " +
+ majorVersion + "." + minorVersion + ", should be " +
+ JAVA_MAJOR_VERSION + "." + JAVA_MINOR_VERSION);
+ pool.indexPool();
+ int flags = in.nextChar();
+ Name name = readClassName(in.nextChar());
+ if (c.fullName() != name)
+ throw new IOException("class file '" + c.fullName() +
+ "' contains wrong class " + name);
+ // todo: correct flag transition
+ c.flags = transFlags(flags);
+ if ((c.flags & Modifiers.ABSTRACT) != 0)
+ c.flags = c.flags & ~Modifiers.ABSTRACT | Modifiers.ABSTRACTCLASS;
+ Type supertpe = readClassType(in.nextChar());
+ Type[] basetpes = new Type[in.nextChar() + 1];
+ this.locals = new Scope();
+ this.statics = new Scope();
+ this.constr = new Scope();
+ // set type of class
+ Type classType = Type.compoundType(basetpes, locals, c);
+ c.setInfo(classType, phaseId);
+ // set type of statics
+ Symbol staticsClass = c.module().moduleClass();
+ Type staticsInfo = Type.compoundType(Type.EMPTY_ARRAY, statics, staticsClass);
+ staticsClass.setInfo(staticsInfo, phaseId);
+ c.module().setInfo(Type.TypeRef(staticsClass.owner().thisType(),
+ staticsClass, Type.EMPTY_ARRAY));
+ basetpes[0] = supertpe;
+ for (int i = 1; i < basetpes.length; i++)
+ basetpes[i] = readClassType(in.nextChar());
+ int fieldCount = in.nextChar();
+ for (int i = 0; i < fieldCount; i++)
+ parseField();
+ int methodCount = in.nextChar();
+ for (int i = 0; i < methodCount; i++)
+ parseMethod();
+ // set constructor type to the declared type
+ Symbol[] constrs = constr.elements();
+ if (constrs.length != 0) {
+ assert constrs.length == 1;
+ c.constructor().setInfo(constrs[0].info(), phaseId);
+ } else {
+ Type constrtype = ((c.flags & Modifiers.INTERFACE) != 0)
+ ? Type.PolyType(Symbol.EMPTY_ARRAY, ctype)
+ : Type.MethodType(new Symbol[]{Symbol.NONE}, ctype);
+ c.constructor().setInfo(constrtype, phaseId);
+ }
+ attrib.readAttributes(c, classType, CLASS_ATTR);
+ //System.out.println("dynamic class: " + c);
+ //System.out.println("statics class: " + staticsClass);
+ //System.out.println("module: " + c.module());
+ //System.out.println("modules class: " + c.module().type().symbol());
+ } catch (RuntimeException e) {
+ e.printStackTrace();
+ throw new IOException("bad class file (" + e.getMessage() + ")");
+ }
+ }
+
+ /** convert Java modifiers into Scala flags
+ */
+ public int transFlags(int flags) {
+ int res = 0;
+ if (((flags & 0x0007) == 0) ||
+ ((flags & 0x0002) != 0))
+ res |= Modifiers.PRIVATE;
+ else if ((flags & 0x0004) != 0)
+ res |= Modifiers.PROTECTED;
+ if ((flags & 0x0400) != 0)
+ res |= Modifiers.ABSTRACT;
+ if ((flags & 0x0010) != 0)
+ res |= Modifiers.FINAL;
+ if ((flags & 0x0200) != 0)
+ res |= Modifiers.INTERFACE | Modifiers.ABSTRACTCLASS;
+ return res | Modifiers.JAVA;
+ }
+
+ /** read a class name
+ */
+ protected Name readClassName(int i) {
+ return (Name)pool.readPool(i);
+ }
+
+ /** read a class name and return the corresponding class type
+ */
+ protected Type readClassType(int i) {
+ if (i == 0)
+ return defs.ANY_TYPE;
+ Type res = defs.getJavaType((Name)pool.readPool(i));
+ if (res == Type.ErrorType)
+ global.error("unknown class reference " + pool.readPool(i));
+ if (res.symbol() == defs.JAVA_OBJECT_TYPE.symbol())
+ return defs.ANYREF_TYPE;
+ else
+ return res;
+ }
+
+ /** read a signature and return it as a type
+ */
+ protected Type readType(int i) {
+ Name sig = pool.readExternal(i);
+ return sigs.sigToType(Name.names, sig.index, sig.length());
+ }
+
+ /** read a field
+ */
+ protected void parseField() {
+ int flags = in.nextChar();
+ Name name = (Name)pool.readPool(in.nextChar());
+ Type type = readType(in.nextChar());
+ int mods = transFlags(flags);
+ if ((flags & 0x0010) == 0)
+ mods |= Modifiers.MUTABLE;
+ Symbol owner = c;
+ if ((flags & 0x0008) != 0)
+ owner = c.module().moduleClass();
+ Symbol s = new TermSymbol(Position.NOPOS, name, owner, mods);
+ s.setInfo(type, phaseId);
+ attrib.readAttributes(s, type, FIELD_ATTR);
+ ((flags & 0x0008) != 0 ? statics : locals).enterOrOverload(s);
+ }
+
+ /** read a method
+ */
+ protected void parseMethod() {
+ int flags = in.nextChar();
+ Name name = (Name)pool.readPool(in.nextChar());
+ Type type = readType(in.nextChar());
+ if (CONSTR_N.equals(name)) {
+ Symbol s = TermSymbol.newConstructor(c, transFlags(flags));
+ // kick out protected, package visible or
+ // private constructors
+ if (((flags & 0x0004) != 0) ||
+ ((flags & 0x0002) != 0) ||
+ ((flags & 0x0007) == 0)) {
+ attrib.readAttributes(s, type, METH_ATTR);
+ return;
+ }
+ switch (type) {
+ case MethodType(Symbol[] vparams, _):
+ if (c == defs.OBJECT_CLASS)
+ type = Type.PolyType(Symbol.EMPTY_ARRAY, ctype);
+ else
+ type = Type.MethodType(vparams, ctype);
+ break;
+ default:
+ throw new ApplicationError();
+ }
+ s.setInfo(type, phaseId);
+ attrib.readAttributes(s, type, METH_ATTR);
+ //System.out.println("-- enter " + s);
+ constr.enterOrOverload(s);
+ } else {
+ Symbol s = new TermSymbol(
+ Position.NOPOS, name,
+ ((flags & 0x0008) != 0) ? c.module().moduleClass() : c,
+ transFlags(flags));
+ s.setInfo(type, phaseId);
+ attrib.readAttributes(s, type, METH_ATTR);
+ ((flags & 0x0008) != 0 ? statics : locals).enterOrOverload(s);
+ }
+ }
+}
diff --git a/sources/scalac/symtab/classfile/ConstantPool.java b/sources/scalac/symtab/classfile/ConstantPool.java
new file mode 100644
index 0000000000..4260b9e6ad
--- /dev/null
+++ b/sources/scalac/symtab/classfile/ConstantPool.java
@@ -0,0 +1,183 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab.classfile;
+
+import scalac.*;
+import scalac.symtab.*;
+import scalac.util.*;
+
+public class ConstantPool implements ClassfileConstants {
+
+ AbstractFileReader in;
+ Signatures sigparser;
+
+ /** the objects of the constant pool
+ */
+ protected Object[] poolObj;
+
+ /** for every constant pool entry, an index into in.buf where the
+ * defining section of the entry is found
+ */
+ protected int[] poolIdx;
+
+ /** constructor
+ */
+ protected ConstantPool(AbstractFileReader in, Signatures sigparser) {
+ this.in = in;
+ this.sigparser = sigparser;
+ }
+
+ /** index all constant pool entries, writing their start
+ * addresses into poolIdx
+ */
+ public void indexPool() {
+ poolIdx = new int[in.nextChar()];
+ poolObj = new Object[poolIdx.length];
+ int i = 1;
+ while (i < poolIdx.length) {
+ poolIdx[i++] = in.bp;
+ byte tag = in.nextByte();
+ switch (tag) {
+ case CONSTANT_UTF8:
+ case CONSTANT_UNICODE: {
+ int len = in.nextChar();
+ in.skip(len);
+ break;
+ }
+ case CONSTANT_CLASS:
+ case CONSTANT_STRING:
+ in.skip(2);
+ break;
+ case CONSTANT_FIELDREF:
+ case CONSTANT_METHODREF:
+ case CONSTANT_INTFMETHODREF:
+ case CONSTANT_NAMEANDTYPE:
+ case CONSTANT_INTEGER:
+ case CONSTANT_FLOAT:
+ in.skip(4);
+ break;
+ case CONSTANT_LONG:
+ case CONSTANT_DOUBLE:
+ in.skip(8);
+ i++;
+ break;
+ default:
+ throw new RuntimeException("bad constant pool tag: " + tag +
+ " at " + (in.bp - 1));
+ }
+ }
+ }
+
+ /** if name is an array type or class signature, return the
+ * corresponding type; otherwise return a class definition with given name
+ */
+ protected Object classOrType(Name name) {
+ if ((name.sub(0) == '[') || (name.sub(name.length() - 1) == ';')) {
+ byte[] ascii = name.toAscii();
+ return sigparser.sigToType(ascii, 0, ascii.length);
+ } else
+ return name;
+ }
+
+ /** read constant pool entry at start address i, use poolObj as a cache.
+ */
+ public Object readPool(int i) {
+ if (poolObj[i] != null)
+ return poolObj[i];
+ int index = poolIdx[i];
+ if (index == 0)
+ return null;
+ switch (in.byteAt(index)) {
+ case CONSTANT_UTF8:
+ poolObj[i] = Name.fromAscii(in.buf, index + 3, in.getChar(index + 1));
+ break;
+
+ case CONSTANT_UNICODE:
+ throw new RuntimeException("can't read unicode strings in classfiles");
+
+ case CONSTANT_CLASS:
+ poolObj[i] = classOrType(readExternal(in.getChar(index + 1)));
+ break;
+
+ case CONSTANT_FIELDREF: {
+ //Symbol owner = (Symbol)readPool(in.getChar(index + 1));
+ //NameAndType nt = (NameAndType)readPool(in.getChar(index + 3));
+ //poolObj[i] = new TermSymbol(Kinds.VAR, Position.NOPOS, nt.name, owner, 0)
+ // .type(sigparser.sigToType(Name.names, nt.sig.index, nt.sig.length()));
+ throw new RuntimeException("can't read constant_fieldrefs in classfiles");
+ }
+
+ case CONSTANT_METHODREF:
+ case CONSTANT_INTFMETHODREF: {
+ //Symbol owner = (Symbol)readPool(in.getChar(index + 1));
+ //NameAndType nt = (NameAndType)readPool(in.getChar(index + 3));
+ //poolObj[i] = new TermSymbol(Kinds.FUN, Position.NOPOS, nt.name, owner, 0)
+ // .type(sigparser.sigToType(Name.names, nt.sig.index, nt.sig.length()));
+ throw new RuntimeException("can't read constant_methodrefs in classfiles");
+ }
+
+ case CONSTANT_NAMEANDTYPE:
+ poolObj[i] = new NameAndType((Name)readPool(in.getChar(index + 1)),
+ readExternal(in.getChar(index + 3)));
+ break;
+
+ case CONSTANT_STRING:
+ case CONSTANT_INTEGER:
+ case CONSTANT_FLOAT:
+ case CONSTANT_LONG:
+ case CONSTANT_DOUBLE:
+ throw new RuntimeException("can't read constants in classfiles");
+
+ default:
+ throw new RuntimeException("bad constant pool tag: " + in.byteAt(index));
+ }
+ return poolObj[i];
+ }
+
+ /** return internal representation of buf[offset..offset+len-1],
+ * converting '/' to '.'
+ */
+ public byte[] internalize(byte[] buf, int offset, int len) {
+ byte[] translated = new byte[len];
+ for (int j = 0; j < len; j++) {
+ byte b = buf[offset + j];
+ if (b == '/')
+ translated[j] = '.';
+ else
+ translated[j] = b;
+ }
+ return translated;
+ }
+
+ /** read a constant pool string and convert to internal representation.
+ */
+ public Name readExternal(int i) {
+ if (poolObj[i] == null) {
+ int index = poolIdx[i];
+ if (in.byteAt(index) == CONSTANT_UTF8) {
+ int len = in.getChar(index + 1);
+ byte[] translated = internalize(in.buf, index + 3, len);
+ poolObj[i] = Name.fromAscii(translated, 0, len);
+ }
+ }
+ return (Name)poolObj[i];
+ }
+
+ /** the name and type signature of a method or field
+ */
+ public static final class NameAndType {
+ public Name name;
+ public Name sig;
+
+ public NameAndType(Name name, Name sig) {
+ this.name = name;
+ this.sig = sig;
+ }
+ }
+}
diff --git a/sources/scalac/symtab/classfile/JavaTypeCreator.java b/sources/scalac/symtab/classfile/JavaTypeCreator.java
new file mode 100644
index 0000000000..5bdc9402ba
--- /dev/null
+++ b/sources/scalac/symtab/classfile/JavaTypeCreator.java
@@ -0,0 +1,82 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab.classfile;
+
+import scalac.Global;
+import scalac.util.*;
+import scalac.symtab.*;
+import Type.*;
+
+
+public class JavaTypeCreator implements JavaTypeFactory {
+
+ protected Global global;
+
+ public JavaTypeCreator(Global global) {
+ this.global = global;
+ }
+
+ public Type byteType() {
+ return global.definitions.BYTE_TYPE;
+ }
+
+ public Type shortType() {
+ return global.definitions.SHORT_TYPE;
+ }
+
+ public Type charType() {
+ return global.definitions.CHAR_TYPE;
+ }
+
+ public Type intType() {
+ return global.definitions.INT_TYPE;
+ }
+
+ public Type longType() {
+ return global.definitions.LONG_TYPE;
+ }
+
+ public Type floatType() {
+ return global.definitions.FLOAT_TYPE;
+ }
+
+ public Type doubleType() {
+ return global.definitions.DOUBLE_TYPE;
+ }
+
+ public Type booleanType() {
+ return global.definitions.BOOLEAN_TYPE;
+ }
+
+ public Type voidType() {
+ return global.definitions.UNIT_TYPE;
+ }
+
+ public Type classType(Name classname) {
+ return global.definitions.getJavaType(classname);
+ }
+
+ public Type arrayType(Type elemtpe) {
+ return global.definitions.arrayType(elemtpe);
+ }
+
+ public Type methodType(Type[] argtpes, Type restpe, Type[] thrown) {
+ Symbol[] args = new Symbol[argtpes.length];
+ for (int i = 0; i < args.length; i++) {
+ args[i] = new TermSymbol(
+ Position.NOPOS, Name.fromString("x" + i), Symbol.NONE, Modifiers.PARAM);
+ args[i].setInfo(argtpes[i]);
+ }
+ return new MethodType(args, restpe);
+ }
+
+ public Type packageType(Name packagename) {
+ return null;
+ }
+}
diff --git a/sources/scalac/symtab/classfile/JavaTypeFactory.java b/sources/scalac/symtab/classfile/JavaTypeFactory.java
new file mode 100644
index 0000000000..8205055bc9
--- /dev/null
+++ b/sources/scalac/symtab/classfile/JavaTypeFactory.java
@@ -0,0 +1,28 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab.classfile;
+
+import scalac.symtab.Type;
+import scalac.util.Name;
+
+public interface JavaTypeFactory {
+ Type byteType();
+ Type shortType();
+ Type charType();
+ Type intType();
+ Type longType();
+ Type floatType();
+ Type doubleType();
+ Type booleanType();
+ Type voidType();
+ Type classType(Name classname);
+ Type arrayType(Type elemtpe);
+ Type methodType(Type[] argtpes, Type restpe, Type[] thrown);
+ Type packageType(Name packagename);
+}
diff --git a/sources/scalac/symtab/classfile/PackageParser.java b/sources/scalac/symtab/classfile/PackageParser.java
new file mode 100644
index 0000000000..50fcb46b00
--- /dev/null
+++ b/sources/scalac/symtab/classfile/PackageParser.java
@@ -0,0 +1,129 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab.classfile;
+
+import scalac.*;
+import scalac.symtab.*;
+import scalac.util.*;
+import java.io.*;
+
+public class PackageParser extends Type.LazyType {
+
+ /** the global compilation environment
+ */
+ protected Global global;
+
+ /** the class parser
+ */
+ public ClassParser classCompletion;
+
+ public PackageParser(Global global) {
+ this.global = global;
+ this.classCompletion = new ClassParser(global);
+ }
+
+ /** complete package type symbol p by loading all package members
+ */
+ public void complete(Symbol p) {
+ long msec = System.currentTimeMillis();
+ Scope members = new Scope();
+ String dirname = null;
+ Name name = p.fullName();
+ if (name.length() == 0) {
+ // includeMembers(AbstractFile.open(null, "."), p, members, false);
+ } else {
+ dirname = externalizeFileName(name);
+ assert !dirname.startsWith("com") : p;//debug
+ if (!dirname.endsWith("/"))
+ dirname += "/";
+ }
+ String[] base = global.classPath.components();
+ for (int i = 0; i < base.length; i++) {
+ includeMembers(
+ AbstractFile.open(base[i], dirname), p, members, dirname != null);
+ }
+ p.setInfo(Type.compoundType(Type.EMPTY_ARRAY, members, p));
+ if (dirname == null)
+ dirname = "anonymous package";
+ global.operation("scanned " + dirname + " in " +
+ (System.currentTimeMillis() - msec) + "ms");
+ }
+
+ /** read directory of a classpath directory and include members
+ * in package/module scope
+ */
+ protected void includeMembers(AbstractFile dir, Symbol p, Scope locals,
+ boolean inclClasses) {
+ if (dir == null)
+ return;
+ String[] filenames = null;
+ try {
+ if ((filenames = dir.list()) == null)
+ return;
+ for (int j = 0; j < filenames.length; j++) {
+ String fname = filenames[j];
+ if (inclClasses && fname.endsWith(".class")) {
+ Name n = Name.fromString(fname.substring(0, fname.length() - 6))
+ .toTypeName();
+ ClassSymbol clazz = new ClassSymbol(n, p, classCompletion);
+ clazz.constructor().setInfo(
+ classCompletion.staticsParser(clazz));
+ // enter class
+ locals.enter(clazz);
+ locals.enter(clazz.constructor());
+ // enter module, except for scala.Object class
+ // todo: why not there also?.
+ if (!(n == Names.Object.toTypeName() &&
+ p.fullName().toTermName() == Names.scala)) {
+ Scope.Entry e = locals.lookupEntry(clazz.module().name);
+ if (e != Scope.Entry.NONE) {
+ // we already have a package of the same name; delete it
+ locals.unlink(e);
+ }
+ locals.enter(clazz.module());
+ }
+ } else if (fname.endsWith("/") && !fname.equals("META-INF/")) {
+ Name n = Name.fromString(fname.substring(0, fname.length() - 1));
+ if (locals.lookup(n) == Symbol.NONE) {
+ TermSymbol module = TermSymbol.newJavaPackageModule(n, p, this);
+ locals.enter(module);
+ }
+ } else if (fname.endsWith(".scala")) {
+ Name n = Name.fromString(fname.substring(0, fname.length() - 6))
+ .toTypeName();
+ if (locals.lookup(n) == Symbol.NONE) {
+ SourceCompleter completer = new SourceCompleter(global,
+ dir.getPath() + File.separatorChar + fname);
+ ClassSymbol clazz = new ClassSymbol(n, p, completer);
+ clazz.constructor().setInfo(completer);
+ clazz.module().setInfo(completer);
+ // enter class
+ locals.enter(clazz);
+ locals.enter(clazz.constructor());
+ locals.enter(clazz.module());
+ }
+ }
+ }
+ } catch (IOException e) {
+ }
+ }
+
+ /** return external representation of file name s,
+ * converting '.' to File.separatorChar
+ */
+
+ public String externalizeFileName(Name n) {
+ if ((n == null) || (n.length() == 0))
+ return ".";
+ byte[] ascii = n.toAscii();
+ String s = SourceRepresentation.ascii2string(
+ ascii, 0, ascii.length);
+ return s.replace('.', File.separatorChar);
+ }
+}
diff --git a/sources/scalac/symtab/classfile/Signatures.java b/sources/scalac/symtab/classfile/Signatures.java
new file mode 100644
index 0000000000..9676882aed
--- /dev/null
+++ b/sources/scalac/symtab/classfile/Signatures.java
@@ -0,0 +1,122 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab.classfile;
+
+import scalac.*;
+import scalac.symtab.*;
+import scalac.util.*;
+import java.util.*;
+import Type.*;
+
+public class Signatures {
+
+ /** signature constants
+ */
+ Name BYTE_SIG = Name.fromString("B");
+ Name SHORT_SIG = Name.fromString("S");
+ Name CHAR_SIG = Name.fromString("C");
+ Name INT_SIG = Name.fromString("I");
+ Name LONG_SIG = Name.fromString("J");
+ Name FLOAT_SIG = Name.fromString("F");
+ Name DOUBLE_SIG = Name.fromString("D");
+ Name BOOLEAN_SIG = Name.fromString("Z");
+ Name VOID_SIG = Name.fromString("V");
+ Name CLASS_SIG = Name.fromString("L");
+ Name ARRAY_SIG = Name.fromString("[");
+ Name ARGBEGIN_SIG = Name.fromString("(");
+ Name ARGEND_SIG = Name.fromString(")");
+
+ Global global;
+ JavaTypeFactory make;
+
+
+ public Signatures(Global global, JavaTypeFactory make) {
+ this.make = make;
+ this.global = global;
+ }
+
+ /** the type represented by signature[offset..].
+ */
+ protected byte[] signature;
+ protected int sigp;
+ protected int limit;
+
+ public Type sigToType(byte[] sig, int offset, int len) {
+ signature = sig;
+ sigp = offset;
+ limit = offset + len;
+ return sigToType();
+ }
+
+ protected Type sigToType() {
+ switch (signature[sigp]) {
+ case 'B':
+ sigp++;
+ return make.byteType();
+ case 'C':
+ sigp++;
+ return make.charType();
+ case 'D':
+ sigp++;
+ return make.doubleType();
+ case 'F':
+ sigp++;
+ return make.floatType();
+ case 'I':
+ sigp++;
+ return make.intType();
+ case 'J':
+ sigp++;
+ return make.longType();
+ case 'L':
+ sigp++;
+ int start = sigp;
+ while (signature[sigp] != ';')
+ sigp++;
+ return make.classType(Name.fromAscii(signature, start, (sigp++) - start));
+ case 'S':
+ sigp++;
+ return make.shortType();
+ case 'V':
+ sigp++;
+ return make.voidType();
+ case 'Z':
+ sigp++;
+ return make.booleanType();
+ case '[':
+ sigp++;
+ while (('0' <= signature[sigp]) && (signature[sigp] <= '9'))
+ sigp++;
+ return make.arrayType(sigToType());
+ case '(':
+ return make.methodType(sigToTypes(')'), sigToType(), Type.EMPTY_ARRAY);
+ default:
+ global.error("bad signature: " +
+ SourceRepresentation.ascii2string(signature, sigp, 1));
+ return Type.ErrorType;
+ }
+ }
+
+ protected Type[] sigToTypes(char terminator) {
+ sigp++;
+ return sigToTypes(terminator, 0);
+ }
+
+ protected Type[] sigToTypes(char terminator, int i) {
+ if (signature[sigp] == terminator) {
+ sigp++;
+ return new Type[i];
+ } else {
+ Type t = sigToType();
+ Type[] vec = sigToTypes(terminator, i+1);
+ vec[i] = t;
+ return vec;
+ }
+ }
+}