summaryrefslogtreecommitdiff
path: root/sources/scalac/typechecker/Analyzer.java
diff options
context:
space:
mode:
Diffstat (limited to 'sources/scalac/typechecker/Analyzer.java')
-rw-r--r--sources/scalac/typechecker/Analyzer.java1975
1 files changed, 1975 insertions, 0 deletions
diff --git a/sources/scalac/typechecker/Analyzer.java b/sources/scalac/typechecker/Analyzer.java
new file mode 100644
index 0000000000..5558239d1c
--- /dev/null
+++ b/sources/scalac/typechecker/Analyzer.java
@@ -0,0 +1,1975 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+**
+** $Id$
+\* */
+
+// todo: (0) propagate target type in cast.
+// todo: (1) check that only stable defs override stable defs
+
+package scalac.typechecker;
+
+import scalac.*;
+import scalac.util.*;
+import scalac.ast.*;
+import scalac.ast.printer.*;
+import scalac.symtab.*;
+import Tree.*;
+import java.util.HashMap;
+import java.util.Vector;
+
+public class Analyzer extends Transformer implements Modifiers, Kinds {
+
+ private final Definitions definitions;
+ private final DeSugarize desugarize;
+ private final AnalyzerPhase descr;
+ final Infer infer;
+
+ public Analyzer(Global global, AnalyzerPhase descr) {
+ super(global, descr);
+ this.definitions = global.definitions;
+ this.descr = descr;
+ this.infer = new Infer(this);
+ this.desugarize = new DeSugarize(this, global);
+ }
+
+ /** Phase variables, used and set in transformers;
+ */
+ private Unit unit;
+ private Context context;
+ private Type pt;
+ private int mode;
+
+ public void apply() {
+ int errors = global.reporter.errors();
+ for (int i = 0; i < global.units.length; i++) {
+ enterUnit(global.units[i]);
+ }
+ super.apply();
+ int n = descr.newSources.size();
+ while (n > 0) {
+ int l = global.units.length;
+ Unit[] newUnits = new Unit[l + n];
+ System.arraycopy(global.units, 0, newUnits, 0, l);
+ for (int i = 0; i < n; i++)
+ newUnits[i + l] = (Unit)descr.newSources.get(i);
+ global.units = newUnits;
+ descr.newSources.clear();
+ for (int i = l; i < newUnits.length; i++) {
+ apply(newUnits[i]);
+ }
+ n = descr.newSources.size();
+ }
+ }
+
+ public void enterUnit(Unit unit) {
+ enter(new Context(Tree.Empty, descr.startContext), unit);
+ }
+
+ public void enter(Context context, Unit unit) {
+ assert this.unit == null : "start unit non null for " + unit;
+ this.unit = unit;
+ this.context = context;
+ descr.contexts.put(unit, context);
+ enterSyms(unit.body);
+ this.unit = null;
+ this.context = null;
+ }
+
+ public void lateEnter(Unit unit, Symbol sym) {
+ assert sym.pos == Position.NOPOS : sym;
+ enterUnit(unit);
+ if (sym.pos == Position.NOPOS) {
+ sym.setInfo(Type.ErrorType);
+ String kind;
+ if (sym.name.isTermName()) kind = "module or method ";
+ else if (sym.name.isTypeName()) kind = "class ";
+ else kind = "constructor ";
+ throw new Type.Error("file " + unit.source + " does not define public " +
+ kind + sym.name);
+ } else {
+ descr.newSources.add(unit);
+ }
+ }
+
+ public void apply(Unit unit) {
+ global.log("checking " + unit);
+ assert this.unit == null : "start unit non null for " + unit;
+ this.unit = unit;
+ this.context = (Context)descr.contexts.remove(unit);
+ assert this.context != null : "could not find context for " + unit;
+ //context.imports = context.outer.imports;
+ unit.body = transformStatSeq(unit.body, Symbol.NONE);
+ /** todo: check what this is for
+ if (global.target == global.TARGET_JAVA && unit.errors == 0) {
+ unit.symdata = new SymData(unit);
+ }
+ */
+ this.unit = null;
+ this.context = null;
+ global.operation("checked " + unit);
+ }
+
+ /** Mode constants
+ */
+ static final int NOmode = 0x000;
+ static final int EXPRmode = 0x001; // these 4 modes are mutually exclusive.
+ static final int PATTERNmode = 0x002;
+ static final int CONSTRmode = 0x004;
+ static final int TYPEmode = 0x008;
+
+ static final int FUNmode = 0x10; // orthogonal to above. When set
+ // we are looking for a method or constructor
+
+ static final int POLYmode = 0x020; // orthogonal to above. When set
+ // expression types can be polymorphic.
+
+ static final int QUALmode = 0x040; // orthogonal to above. When set
+ // expressions may be packages and
+ // Java statics modules.
+
+// Helper definitions ---------------------------------------------------------
+
+ /** The qualifier type of a potential application of the `match' method.
+ * or NoType, if this is something else.
+ */
+ private Type matchQualType(Tree fn) {
+ switch (fn) {
+ case Select(Tree qual, _):
+ if (fn.symbol() == definitions.OBJECT_TYPE.lookup(Names.match))
+ return qual.type.widen();
+ break;
+ case TypeApply(Tree fn1, _):
+ return matchQualType(fn1);
+ case Ident(_):
+ if (fn.symbol() == definitions.OBJECT_TYPE.lookup(Names.match))
+ return context.enclClass.owner.type();
+ break;
+ }
+ return fn.type == Type.ErrorType ? Type.ErrorType : Type.NoType;
+ }
+
+ private Tree deepCopy(Tree tree) {
+ switch (tree) {
+ case Ident(Name name):
+ return make.Ident(tree.pos, name)
+ .setSymbol(tree.symbol()).setType(tree.type);
+ case Select(Tree qual, Name name):
+ return make.Select(tree.pos, deepCopy(qual), name)
+ .setSymbol(tree.symbol()).setType(tree.type);
+ default:
+ return tree;
+ }
+ }
+
+ static Name value2TypeName(Object value) {
+ if (value instanceof Character) return Name.fromString("scala.Char");
+ else if (value instanceof Integer) return Name.fromString("scala.Int");
+ else if (value instanceof Long) return Name.fromString("scala.Long");
+ else if (value instanceof Float) return Name.fromString("scala.Float");
+ else if (value instanceof Double) return Name.fromString("scala.Double");
+ else if (value instanceof String) return Name.fromString("java.lang.String");
+ else throw new ApplicationError();
+ }
+
+ Tree error(Tree tree, String msg) {
+ unit.error(tree.pos, msg);
+ if (tree.hasSymbol()) tree = tree.setSymbol(Symbol.ERROR);
+ return tree.setType(Type.ErrorType);
+ }
+
+ void error(int pos, String msg) {
+ unit.error(pos, msg);
+ }
+
+ void typeError(int pos, Type found, Type req) {
+ String explanation = "";
+ switch (found) {
+ case MethodType(_, Type restype):
+ if (infer.isCompatible(restype, req))
+ explanation = "\n possible cause: missing arguments for method or constructor";
+ }
+ error(pos, infer.typeErrorMsg("type mismatch", found, req) + explanation);
+ }
+
+// Name resolution -----------------------------------------------------------
+
+ /** Is `sym' accessible as a member of tree `site' in current context?
+ */
+ boolean isAccessible(Symbol sym, Tree site) {
+ return
+ (sym.flags & (PRIVATE | PROTECTED)) == 0
+ ||
+ accessWithin(sym.owner())
+ ||
+ ((sym.flags & PRIVATE) == 0) &&
+ site.type.symbol().isSubClass(sym.owner()) &&
+ (site instanceof Tree.Super ||
+ isSubClassOfEnclosing(site.type.symbol()));
+ } //where
+
+ /** Are we inside definition of `owner'?
+ */
+ boolean accessWithin(Symbol owner) {
+ Context c = context;
+ while (c != Context.NONE && c.owner != owner) {
+ c = c.outer.enclClass;
+ }
+ return c != Context.NONE;
+ }
+
+ /** Is `clazz' a subclass of an enclosing class?
+ */
+ boolean isSubClassOfEnclosing(Symbol clazz) {
+ Context c = context;
+ while (c != Context.NONE && !clazz.isSubClass(c.owner)) {
+ c = c.outer.enclClass;
+ }
+ return c != Context.NONE;
+ }
+
+// Checking methods ----------------------------------------------------------
+
+ /** Check that symbol's definition is well-formed. This means:
+ * - no conflicting modifiers
+ * - def modifiers only in methods
+ * - declarations only in classes
+ * - classes with abstract members have `abstract' modifier.
+ * - symbols with `override' modifier override some other symbol.
+ */
+ void validate(Symbol sym) {
+ checkNoConflict(sym, ABSTRACT, PRIVATE);
+ checkNoConflict(sym, FINAL, PRIVATE);
+ checkNoConflict(sym, PRIVATE, PROTECTED);
+ checkNoConflict(sym, PRIVATE, OVERRIDE);
+ checkNoConflict(sym, ABSTRACT, FINAL);
+ if ((sym.flags & ABSTRACTCLASS) != 0 && sym.kind != CLASS) {
+ error(sym.pos, "`abstract' modifier can be used only for classes; " +
+ "\nit should be omitted for abstract members");
+ }
+ if ((sym.flags & OVERRIDE) != 0 && sym.kind == CLASS) {
+ error(sym.pos, "`override' modifier ot allowed for classes");
+ }
+ if ((sym.flags & DEF) != 0 && sym.owner().isPrimaryConstructor()) {
+ error(sym.pos, "`def' modifier not allowed for class parameters");
+ }
+ if ((sym.flags & ABSTRACT) != 0) {
+ if (sym.owner().kind != CLASS ||
+ (sym.owner().flags & MODUL) != 0 ||
+ sym.owner().isAnonymousClass()) {
+ error(sym.pos, abstractVarNote(sym,
+ "only classes can have declared but undefined members"));
+ sym.flags &= ~ABSTRACT;
+ }
+ }
+ if ((sym.flags & OVERRIDE) != 0) {
+ int i = -1;
+ if (sym.owner().kind == CLASS) {
+ Type[] parents = sym.owner().info().parents();
+ i = parents.length - 1;
+ while (i >= 0 &&
+ parents[i].lookupNonPrivate(sym.name).kind == NONE)
+ i--;
+ }
+ if (i < 0) {
+ error(sym.pos, sym + " overrides nothing");
+ sym.flags &= ~OVERRIDE;
+ }
+ }
+ }
+
+ /** Check that
+ * - all parents are class types
+ * - supertype conforms to supertypes of all mixin types.
+ * - final classes are only inherited by classes which are
+ * nested within definition of base class, or that occur within same
+ * statement sequence.
+ */
+ void validateParentClasses(Tree[] constrs, Type[] parents) {
+ if (parents.length == 0 || !checkClassType(constrs[0].pos, parents[0])) return;
+ for (int i = 1; i < parents.length; i++) {
+ if (!checkClassType(constrs[i].pos, parents[i])) return;
+ Type[] grandparents = parents[i].parents();
+ if (grandparents.length > 0 && !parents[0].isSubType(grandparents[0]))
+ error(constrs[i].pos, "illegal inheritance;\n " + parents[0] +
+ "does not conform to " + parents[i] + "'s supertype");
+ Symbol bsym = parents[i].symbol();
+ if ((bsym.flags & FINAL) != 0) {
+ // are we in same scope as base type definition?
+ Scope.Entry e = context.scope.lookupEntry(bsym.name);
+ if (e.sym != bsym || e.owner != context.scope) {
+ // we are not within same statement sequence
+ Context c = context;
+ while (c != Context.NONE && c.owner != bsym)
+ c = c.outer;
+ if (c == Context.NONE) {
+ error(constrs[i].pos, "illegal inheritance from final class");
+ }
+ }
+ }
+ }
+ }
+
+ /** Check that type is a class type.
+ */
+ private boolean checkClassType(int pos, Type tp) {
+ switch (tp.unalias()) {
+ case TypeRef(_, Symbol sym, _):
+ if (sym.kind == CLASS) return true;
+ else if (sym.kind == ERROR) return false;
+ break;
+ case ErrorType:
+ return false;
+ }
+ error(pos, "class type expected");
+ return false;
+ }
+
+ /** Check that type is an object type
+ */
+ private Type checkObjectType(int pos, Type tp) {
+ if (tp.isObjectType()) return tp;
+ else {
+ if (tp != Type.ErrorType) error(pos, "object type expected");
+ return Type.ErrorType;
+ }
+ }
+
+ /** 1. Check that only parameterless (uniform) classes are inherited several times.
+ * 2. Check that all type instances of an inherited uniform class are the same.
+ * 3. Check that case classes do not inherit from case classes.
+ */
+ void validateBaseTypes(Symbol clazz) {
+ if (clazz.type().parents().length > 1)
+ validateBaseTypes(clazz, clazz.type(),
+ new boolean[clazz.closure().length], 0);
+ }
+ //where
+ void validateBaseTypes(Symbol clazz, Type tp, boolean[] seen, int start) {
+ Symbol baseclazz = tp.symbol();
+ if (baseclazz.kind == CLASS) {
+ int index = clazz.closurePos(baseclazz);
+ if (seen[index]) {
+ // check that only uniform classes are inherited several times.
+ if (!clazz.isCompoundSym() && !baseclazz.isTrait()) {
+ error(clazz.pos, "illegal inheritance;\n" + clazz +
+ " inherits " + baseclazz + " twice");
+ }
+ // check no two different type instances of same class
+ // are inherited.
+ Type tp1 = clazz.closure()[index];
+ if (!tp1.isSameAs(tp)) {
+ if (clazz.isCompoundSym())
+ error(clazz.pos,
+ "illegal combination;\n " + "compound type " +
+ " combines different type instances of " +
+ baseclazz + ":\n" + tp + " and " + tp1);
+ else
+ error(clazz.pos, "illegal inheritance;\n " + clazz +
+ " inherits different type instances of " +
+ baseclazz + ":\n" + tp + " and " + tp1);
+ }
+ }
+ // check that case classes do not inherit from case classes
+ if (clazz.isCaseClass() && baseclazz.isCaseClass())
+ error(clazz.pos, "illegal inheritance;\n " + "case " + clazz +
+ "inherits from other case " + baseclazz);
+
+ seen[index] = true;
+ Type[] parents = tp.parents();
+ for (int i = parents.length - 1; i >= start; i--) {
+ validateBaseTypes(clazz, parents[i].unalias(), seen, i == 0 ? 0 : 1);
+ }
+ }
+ }
+
+ /** Check that found type conforms to required one.
+ */
+ Type checkType(int pos, Type found, Type required) {
+ if (found.isSubType(required)) return found;
+ else {
+ typeError(pos, found, required);
+ if (global.debug) {
+ Type.debugSwitch = true;
+ found.isSubType(required);
+ Type.debugSwitch = false;
+ }
+ return Type.ErrorType;
+ }
+ }
+
+ /** Check that type is eta-expandable (i.e. no `def' parameters)
+ */
+ void checkEtaExpandable(int pos, Type tp) {
+ switch (tp) {
+ case MethodType(Symbol[] params, Type restype):
+ for (int i = 0; i < params.length; i++) {
+ if ((params[i].flags & DEF) != 0)
+ error(pos, "method with `def' parameters needs to be fully applied");
+ }
+ checkEtaExpandable(pos, restype);
+ }
+ }
+
+ /** Check that `sym' does not contain both `flag1' and `flag2'
+ */
+ void checkNoConflict(Symbol sym, int flag1, int flag2) {
+ if ((sym.flags & (flag1 | flag2)) == (flag1 | flag2)) {
+ if (flag1 == ABSTRACT)
+ error(sym.pos, "abstract member may not have " +
+ Modifiers.Helper.toString(flag2) + " modifier");
+ else
+ error(sym.pos, "illegal combination of modifiers: " +
+ Modifiers.Helper.toString(flag1) + " and " +
+ Modifiers.Helper.toString(flag2));
+ }
+ }
+
+ /** Check that
+
+ /** Check that type does not refer to components defined in current scope.
+ */
+ Type checkNoEscape(int pos, Type tp) {
+ try {
+ return checkNoEscapeMap.apply(tp);
+ } catch (Type.Error ex) {
+ error(pos, ex.msg);
+ return Type.ErrorType;
+ }
+ }
+ //where
+ private Type.Map checkNoEscapeMap = new Type.Map() {
+ public Type apply(Type t) {
+ switch (t.unalias()) {
+ case TypeRef(ThisType(_), Symbol sym, Type[] args):
+ Scope.Entry e = context.scope.lookupEntry(sym.name);
+ if (e.sym == sym && e.owner == context.scope) {
+ throw new Type.Error(
+ "type " + t + " escapes its defining scope");
+ } else {
+ map(args);
+ return t;
+ }
+ case SingleType(ThisType(_), Symbol sym):
+ Scope.Entry e = context.scope.lookupEntry(sym.name);
+ if (e.sym == sym && e.owner == context.scope) {
+ return apply(t.widen());
+ } else {
+ return t;
+ }
+ default:
+ return map(t);
+ }
+ }};
+
+ /** Check that tree represents a pure definition.
+ */
+ void checkPureDef(Tree tree, Symbol clazz) {
+ if (!TreeInfo.isPureDef(tree) && tree.type != Type.ErrorType)
+ error(tree.pos, clazz + " may contain only pure definitions");
+ }
+
+ /** Check that tree represents a pure definition.
+ */
+ void checkTrait(Tree tree, Symbol clazz) {
+ if (!TreeInfo.isPureConstr(tree) && tree.type != Type.ErrorType)
+ error(tree.pos, " " + clazz + " may inherit only from stable trait constructors");
+ }
+
+ /** Check that tree is a stable expression .
+ */
+ Tree checkStable(Tree tree) {
+ if (TreeInfo.isPureExpr(tree) || tree.type == Type.ErrorType) return tree;
+ new TextTreePrinter().print(tree).end();//debug
+ System.out.println(" " + tree.type);//debug
+ return error(tree, "stable identifier required");
+ }
+
+ /** Check all members of class `clazz' for overriding conditions.
+ */
+ void checkAllOverrides(Symbol clazz) {
+ Type[] closure = clazz.closure();
+ for (int i = 0; i < closure.length; i++) {
+ for (Scope.SymbolIterator it = closure[i].members().iterator();
+ it.hasNext();) {
+ Symbol other = it.next();
+ Symbol member = clazz.info().lookup(other.name);
+ if (other != member && member.kind != NONE)
+ checkOverride(clazz, member, other);
+ if ((member.flags & ABSTRACT) != 0 &&
+ clazz.kind == CLASS &&
+ (clazz.flags & ABSTRACTCLASS) == 0) {
+ if (clazz.isAnonymousClass())
+ error(clazz.pos, "object creation impossible, since " +
+ member + member.locationString() + " is not defined");
+ else
+ error(clazz.pos,
+ clazz + abstractVarNote(
+ member, " needs to be abstract; it does not define " +
+ member + member.locationString()));
+ clazz.flags |= ABSTRACTCLASS;
+ }
+ }
+ }
+ }
+
+ /** Check that all conditions for overriding `other' by `member' are met.
+ */
+ void checkOverride(Symbol clazz, Symbol member, Symbol other) {
+ int pos;
+ if (member.owner() == clazz) pos = member.pos;
+ else if (!member.owner().isSubClass(other.owner())) pos = context.tree.pos;
+ else return; // everything was already checked elsewhere
+
+ if ((member.flags & PRIVATE) != 0) {
+ overrideError(pos, member, other, "should not be private");
+ } else if ((other.flags & PROTECTED) != 0 && (member.flags & PROTECTED) == 0) {
+ overrideError(pos, member, other, "needs `protected' modifier");
+ } else if ((other.flags & FINAL) != 0) {
+ overrideError(pos, member, other, "cannot override final member");
+ } else if ((other.flags & ABSTRACT) == 0 && ((member.flags & OVERRIDE) == 0)) {
+ overrideError(pos, member, other, "needs `override' modifier");
+ } else {
+ Type self = clazz.thisType();
+ switch (other.kind) {
+ case CLASS:
+ overrideError(pos, member, other, "cannot override a class");
+ break;
+ case ALIAS:
+ if (!self.memberInfo(member).isSameAs(self.memberInfo(other)))
+ overrideTypeError(pos, member, other, self);
+ break;
+ default:
+ if (other.isConstructor())
+ overrideError(pos, member, other, "cannot override a class constructor");
+ if (!self.memberInfo(member).isSubType(self.memberInfo(other)))
+ overrideTypeError(pos, member, other, self);
+ }
+ }
+ }
+
+ void overrideError(int pos, Symbol member, Symbol other, String msg) {
+ if (other.type() != Type.ErrorType && member.type() != Type.ErrorType)
+ error(pos,
+ "error overriding " + other + other.locationString() +
+ "; " + member + member.locationString() + " " + msg);
+ }
+
+ void overrideTypeError(int pos, Symbol member, Symbol other, Type site) {
+ if (other.type() != Type.ErrorType && member.type() != Type.ErrorType)
+ error(pos,
+ member + member.locationString() +
+ infoString(member, site.memberInfo(member)) +
+ "\n cannot override " + other + other.locationString() +
+ infoString(other, site.memberInfo(other)));
+ }
+
+ String infoString(Symbol sym, Type symtype) {
+ switch (sym.kind) {
+ case ALIAS: return ", which equals " + symtype;
+ case TYPE: return " bounded by " + symtype;
+ case VAL: return " of type " + symtype;
+ default: return "";
+ }
+ }
+
+ String abstractVarNote(Symbol member, String msg) {
+ String note = ((member.flags & MUTABLE) == 0) ? ""
+ : "\n(Note that variables need to be initialized to be defined)";
+ return msg + note;
+ }
+
+// Entering Symbols ----------------------------------------------------------
+
+ /** If `tree' is a definition, create a symbol for it with a lazily
+ * constructed type, and enter into current scope.
+ */
+ Symbol enterSym(Tree tree) {
+ // todo: handle override qualifiers
+ Symbol owner = context.owner;
+ switch (tree) {
+ case PackageDef(Tree packaged, Tree.Template templ):
+ switch (templ) {
+ case Template(_, Tree[] body):
+ pushContext(tree, context.owner, context.scope);
+ context.imports = null;
+ ((PackageDef) tree).packaged = packaged =
+ transform(packaged, QUALmode);
+ popContext();
+ Symbol pkg = checkStable(packaged).symbol();
+ if (pkg != null && pkg.kind != ERROR) {
+ if (pkg.isPackage()) {
+ pushContext(templ, pkg.moduleClass(), pkg.members());
+ enterSyms(body);
+ popContext();
+ } else {
+ error(tree.pos, "only Java packages allowed for now");
+ }
+ }
+ templ.setSymbol(Symbol.NONE);
+ return null;
+ default:
+ throw new ApplicationError();
+ }
+
+ case ClassDef(int mods, Name name, Tree.TypeDef[] tparams, Tree.ValDef[][] vparams, _, Tree.Template templ):
+ ClassSymbol clazz = new ClassSymbol(tree.pos, name, owner, mods);
+ if (clazz.isLocalClass()) unit.mangler.setMangledName(clazz);
+ enterSym(tree, clazz.constructor());
+ if ((mods & CASE) != 0) {
+ // enter case constructor method.
+ enterInScope(
+ new TermSymbol(
+ tree.pos, name.toTermName(), owner, mods & (ACCESSFLAGS | CASE))
+ .setInfo(new LazyConstrMethodType(tree)));
+ }
+ return enterSym(tree, clazz);
+
+ case ModuleDef(int mods, Name name, _, _):
+ TermSymbol modul = TermSymbol.newModule(tree.pos, name, owner, mods);
+ Symbol clazz = modul.moduleClass();
+ clazz.setInfo(new LazyTreeType(tree));
+ if (clazz.isLocalClass()) unit.mangler.setMangledName(clazz);
+ return enterSym(tree, modul);
+
+ case ValDef(int mods, Name name, _, _):
+ return enterSym(tree, new TermSymbol(tree.pos, name, owner, mods));
+
+ case DefDef(int mods, Name name, _, _, _, _):
+ return enterSym(tree, new TermSymbol(tree.pos, name, owner, mods));
+
+ case TypeDef(int mods, Name name, _, _):
+ int kind = (mods & (ABSTRACT | PARAM)) != 0 ? TYPE : ALIAS;
+ TypeSymbol tsym = new TypeSymbol(kind, tree.pos, name, owner, mods);
+ if (kind == ALIAS)
+ tsym.constructor().setInfo(new LazyTreeType(tree));
+ return enterSym(tree, tsym);
+
+ case Import(Tree expr, Name[] selectors):
+ return enterImport(tree,
+ new TermSymbol(
+ tree.pos,
+ Name.fromString("import " + expr),
+ Symbol.NONE, SYNTHETIC));
+
+ default:
+ return null;
+ }
+ }//where
+
+ /** Enter `sym' in current scope and make it the symbol of `tree'.
+ */
+ private Symbol enterSym(Tree tree, Symbol sym) {
+ //if (global.debug) System.out.println("entering " + sym);//DEBUG
+ sym.setInfo(new LazyTreeType(tree));
+ sym = enterInScope(sym);
+ tree.setSymbol(sym);
+ return sym;
+ }
+
+ /** Make `sym' the symbol of import `tree' and create an entry in
+ * current imports list.
+ */
+ private Symbol enterImport(Tree tree, Symbol sym) {
+ sym.setInfo(new LazyTreeType(tree));
+ tree.setSymbol(sym);
+ context.imports = new ImportList(tree, context.scope, context.imports);
+ return sym;
+ }
+
+ /** Enter symbol `sym' in current scope. Check for double definitions.
+ * Handle overloading.
+ */
+ private Symbol enterInScope(Symbol sym) {
+ // handle double and overloaded definitions
+ Scope.Entry e = context.scope.lookupEntry(sym.name);
+ if (e.owner == context.scope) {
+ Symbol other = e.sym;
+ if (other.isPreloaded()) {
+ // symbol was preloaded from package;
+ // need to overwrite definition.
+ if (global.debug) System.out.println("overwriting " + other);//debug
+ sym.copyTo(other);
+ if (sym.isModule()) {
+ sym.moduleClass().copyTo(
+ other.moduleClass());
+ sym.moduleClass().constructor().copyTo(
+ other.moduleClass().constructor());
+ }
+ return other;
+ } else if (sym.kind == VAL && other.kind == VAL) {
+ // it's an overloaded definition
+ if (((sym.flags ^ other.flags) & SOURCEFLAGS) != 0) {
+ error(sym.pos,
+ "illegal overloaded definition of " + sym +
+ ": modifier lists differ in " +
+ Modifiers.Helper.toString(
+ (sym.flags ^ other.flags) & SOURCEFLAGS));
+ } else {
+ e.setSymbol(other.overloadWith(sym));
+ }
+ } else {
+ error(sym.pos,
+ sym.nameString() + " is already defined as " +
+ other + other.locationString());
+ }
+ } else {
+ context.scope.enter(sym);
+ }
+ return sym;
+ }
+
+ /** Enter all symbols in statement list
+ */
+ public void enterSyms(Tree[] stats) {
+ for (int i = 0; i < stats.length; i++)
+ enterSym(stats[i]);
+ }
+
+// Definining Symbols -------------------------------------------------------
+
+ /** Define symbol associated with `tree' using given `context'.
+ */
+ void defineSym(Tree tree, Unit unit, Infer infer, Context context) {
+ Unit savedUnit = this.unit;
+ this.unit = unit;
+ Context savedContext = this.context;
+ this.context = context;
+ int savedMode = this.mode;
+ this.mode = EXPRmode;
+ Type savedPt = this.pt;
+ this.pt = Type.AnyType;
+
+ Symbol sym = tree.symbol();
+ if (global.debug) System.out.println("defining " + sym);//debug
+ Type owntype;
+ switch (tree) {
+ case ClassDef(int mods, Name name, Tree.TypeDef[] tparams, Tree.ValDef[][] vparams, _, Tree.Template templ):
+ assert (mods & LOCKED) == 0 || sym.isAnonymousClass(): sym; // to catch repeated evaluations
+ ((ClassDef) tree).mods |= LOCKED;
+
+ if ((mods & CASE) != 0 && vparams.length > 0)
+ templ.body = desugarize.addCaseElements(templ.body, vparams[0]);
+
+ pushContext(tree, sym.constructor(), new Scope(context.scope));
+ Symbol[] tparamSyms = enterParams(tparams);
+ Symbol[][] vparamSyms = enterParams(vparams);
+ Type constrtype = makeMethodType(
+ tparamSyms,
+ vparamSyms,
+ Type.TypeRef(sym.owner().thisType(), sym, Symbol.type(tparamSyms)));
+ sym.constructor().setInfo(constrtype);
+ // necessary so that we can access tparams
+ sym.constructor().flags |= INITIALIZED;
+
+ defineTemplate(templ, sym);
+ owntype = templ.type;
+ popContext();
+ break;
+
+ case ModuleDef(int mods, Name name, Tree tpe, Tree.Template templ):
+ Symbol clazz = sym.moduleClass();
+ defineTemplate(templ, clazz);
+ clazz.setInfo(templ.type);
+ if (tpe == Tree.Empty) owntype = clazz.type();
+ else owntype = transform(tpe, TYPEmode).type;
+ break;
+
+ case ValDef(int mods, Name name, Tree tpe, Tree rhs):
+ if (tpe == Tree.Empty) {
+ if (rhs == Tree.Empty) {
+ if ((sym.owner().flags & ACCESSOR) != 0) {
+ // this is the paremeter of a variable setter method.
+ ((ValDef) tree).tpe = tpe =
+ gen.mkType(tree.pos, sym.owner().accessed().type());
+ } else {
+ error(tree.pos, "missing parameter type");
+ ((ValDef) tree).tpe = tpe =
+ gen.mkType(tree.pos, Type.ErrorType);
+ }
+ owntype = tpe.type;
+ } else {
+ ((ValDef) tree).rhs = rhs = transform(rhs, EXPRmode);
+ owntype = rhs.type;
+ if ((sym.flags & MUTABLE) != 0) owntype = owntype.widen();
+ }
+ } else {
+ owntype = transform(tpe, TYPEmode).type;
+ }
+ break;
+
+ case DefDef(int mods, Name name, Tree.TypeDef[] tparams, Tree.ValDef[][] vparams, Tree tpe, Tree rhs):
+ pushContext(tree, sym, new Scope(context.scope));
+ Symbol[] tparamSyms = enterParams(tparams);
+ Symbol[][] vparamSyms = enterParams(vparams);
+ Type restpe;
+ if (tpe == Tree.Empty) {
+ int rhsmode = name.isConstrName() ? CONSTRmode : EXPRmode;
+ ((DefDef) tree).rhs = rhs = transform(rhs, rhsmode);
+ restpe = rhs.type;
+ } else {
+ restpe = transform(tpe, TYPEmode).type;
+ }
+ popContext();
+ owntype = makeMethodType(tparamSyms, vparamSyms, restpe);
+ break;
+
+ case TypeDef(int mods, Name name, Tree.TypeDef[] tparams, Tree rhs):
+ if (sym.kind == TYPE) {
+ pushContext(rhs, context.owner, context.scope);
+ this.context.delayArgs = true;
+ owntype = transform(rhs, TYPEmode).type;
+ owntype.symbol().initialize();//to detect cycles
+ popContext();
+ } else { // sym.kind == ALIAS
+ pushContext(tree, sym, new Scope(context.scope));
+ Symbol[] tparamSyms = enterParams(tparams);
+ sym.constructor().setInfo(Type.PolyType(tparamSyms, Type.NoType));
+ owntype = transform(rhs, TYPEmode).type;
+ popContext();
+ }
+ break;
+
+ case Import(Tree expr, Name[] selectors):
+ Tree expr1 = transform(expr, EXPRmode | QUALmode);
+ ((Import) tree).expr = expr1;
+ checkStable(expr1);
+ owntype = expr1.type;
+ break;
+
+ default:
+ throw new ApplicationError();
+ }
+ sym.setInfo(owntype);
+ validate(sym);
+ if (global.debug) System.out.println("defined " + sym);//debug
+ this.unit = savedUnit;
+ this.context = savedContext;
+ this.mode = savedMode;
+ this.pt = savedPt;
+ }
+
+ /** Definition phase for a template. This enters all symbols in template
+ * into symbol table.
+ */
+ void defineTemplate(Tree.Template templ, Symbol clazz) {
+ // attribute parent constructors
+ Tree[] constrs = transformConstrInvocations(
+ templ.pos, templ.parents, true, Type.AnyType);
+
+ Type[] parents = new Type[constrs.length];
+ for (int i = 0; i < parents.length; i++)
+ parents[i] = constrs[i].type;
+
+ // enter all members
+ Scope members = new Scope();
+ pushContext(templ, clazz, members);
+ if ((clazz.flags & CASE) != 0)
+ templ.body = desugarize.addCaseMethods(templ.body, clazz, parents);
+ templ.body = desugarize.Statements(templ.body, false);
+ enterSyms(templ.body);
+ popContext();
+
+ templ.type = Type.compoundType(parents, members, clazz);
+ }
+
+ Symbol[] enterParams(Tree[] params) {
+ enterSyms(params);
+ return Tree.symbolOf(params);
+ }
+
+ Symbol[][] enterParams(Tree[][] vparams) {
+ Symbol[][] vparamSyms = new Symbol[vparams.length][];
+ for (int i = 0; i < vparams.length; i++) {
+ vparamSyms[i] = enterParams(vparams[i]);
+ }
+ return vparamSyms;
+ }
+
+ Type makeMethodType(Symbol[] tparams, Symbol[][] vparams, Type restpe) {
+ if (tparams.length == 0 && vparams.length == 0) {
+ return Type.PolyType(tparams, restpe);
+ } else {
+ Type result = restpe;
+ for (int i = vparams.length - 1; i >= 0; i--)
+ result = Type.MethodType(vparams[i], result);
+ if (tparams.length != 0)
+ result = Type.PolyType(tparams, result);
+ return result;
+ }
+ }
+
+ /** Re-enter type parameters in current scope.
+ */
+ void reenterParams(Tree[] params) {
+ for (int i = 0; i < params.length; i++)
+ context.scope.enter(params[i].symbol());
+ }
+
+ /** Re-enter value parameters in current scope.
+ */
+ void reenterParams(Tree[][] vparams) {
+ for (int i = 0; i < vparams.length; i++)
+ reenterParams(vparams[i]);
+ }
+
+// Attribution and Transform -------------------------------------------------
+
+ /** Attribute an identifier consisting of a simple name or an outer reference.
+ * @param tree The tree representing the identifier.
+ * @param name The name of the identifier.
+ */
+ Tree transformIdent(Tree tree, Name name) {
+ // find applicable definition and assign to `sym'
+ Symbol sym = Symbol.NONE;
+ Type pre;
+ Type symtype;
+
+ int stopPos = Integer.MIN_VALUE;
+ Context nextcontext = context;
+ while (sym.kind == NONE && nextcontext != Context.NONE) {
+ sym = nextcontext.scope.lookup(name);
+ if (sym.kind != NONE) {
+ stopPos = sym.pos;
+ } else {
+ nextcontext = nextcontext.enclClass;
+ if (nextcontext != Context.NONE) {
+ sym = nextcontext.owner.info().lookup(name);
+ if (sym.kind != NONE) {
+ stopPos = nextcontext.owner.pos;
+ } else {
+ nextcontext = nextcontext.outer;
+ }
+ }
+ }
+ }
+
+ // find applicable import and assign to `sym1'
+ ImportList nextimports = context.imports;
+ ImportList lastimports = null;
+ Symbol sym1 = Symbol.NONE;
+
+// System.out.println("name = " + name + ", pos = " + tree.pos + ", importlist = ");//DEBUG
+// for (ImportList imp = nextimports; imp != null; imp = imp.prev) {
+// new TextTreePrinter().print(" ").print(imp.tree).println().end();//debug
+// }
+
+ while (nextimports != null && nextimports.tree.pos >= tree.pos) {
+ nextimports = nextimports.prev;
+ }
+ while (sym1.kind == NONE &&
+ nextimports != null && nextimports.tree.pos > stopPos) {
+ sym1 = nextimports.importedSymbol(name);
+ lastimports = nextimports;
+ nextimports = nextimports.prev;
+ }
+
+ // evaluate what was found
+ if (sym1.kind == NONE) {
+ if (sym.kind == NONE) {
+ return error(tree, "not found: " + NameTransformer.decode(name));
+ } else {
+ sym.flags |= ACCESSED;
+ if (sym.owner().kind == CLASS)
+ pre = nextcontext.enclClass.owner.thisType();
+ else
+ pre = Type.localThisType;
+ }
+ } else if (sym.kind != NONE && !sym.isPreloaded()) {
+ return error(tree,
+ "reference to " + name + " is ambiguous;\n" +
+ "it is both defined in " + sym.owner() +
+ " and imported subsequently by \n" + nextimports.tree);
+ } else {
+ // check that there are no other applicable imports in same scope.
+ while (nextimports != null &&
+ nextimports.enclscope == lastimports.enclscope) {
+ if (!nextimports.sameImport(lastimports) &&
+ nextimports.importedSymbol(name).kind != NONE) {
+ return error(tree,
+ "reference to " + name + " is ambiguous;\n" +
+ "it is imported twice in the same scope by\n " +
+ lastimports.tree + "\nand " + nextimports.tree);
+ }
+ nextimports = nextimports.prev;
+ }
+ sym = sym1;
+ sym.flags |= (ACCESSED | SELECTOR);
+ Tree qual = checkStable(deepCopy(lastimports.importPrefix()));
+ pre = qual.type;
+ //new TextTreePrinter().print(name + " => ").print(lastimports.tree).print("." + name).println().end();//DEBUG
+ tree = make.Select(tree.pos, qual, name);
+ }
+ symtype = pre.memberType(sym);
+ if (sym.isTerm() && (sym.flags & MUTABLE) == 0 && symtype.isObjectType()) {
+ //System.out.println("making single " + sym + ":" + symtype);//DEBUG
+ symtype = Type.singleType(pre, sym);
+ }
+ //System.out.println(name + ":" + symtype);//DEBUG
+ return tree.setSymbol(sym).setType(symtype);
+ }
+
+ /** Attribute a selection where `tree' is `qual.name'.
+ * `qual' is already attributed.
+ */
+ Tree transformSelect(Tree tree, Tree qual, Name name) {
+ Symbol[] uninst = Symbol.EMPTY_ARRAY;
+ switch (qual.type) {
+ case PolyType(Symbol[] tparams, Type restype):
+ qual = infer.mkTypeApply(qual, tparams, restype, Symbol.type(tparams));
+ uninst = tparams;
+ }
+ Symbol sym = qual.type.lookup(name);
+ if (sym.kind == NONE) {
+ //System.out.println(qual.type + " has members " + qual.type.members());//DEBUG
+ return error(tree,
+ NameTransformer.decode(name) + " is not a member of " + qual.type.widen());
+ } else if (!isAccessible(sym, qual)) {
+ return error(tree, name + " cannot be accessed in " + qual.type.widen());
+ } else {
+ sym.flags |= (ACCESSED | SELECTOR);
+ Type symtype = qual.type.memberType(sym);
+ //System.out.println(sym.name + ":" + symtype);//debug
+ if (uninst.length != 0) {
+ switch (symtype) {
+ case PolyType(Symbol[] tparams, Type restype):
+ symtype = Type.PolyType(
+ tparams, new Infer.VirtualPolyType(uninst, restype));
+ break;
+ default:
+ symtype = new Infer.VirtualPolyType(uninst, symtype);
+ }
+ }
+ if (sym.isTerm() && (sym.flags & MUTABLE) == 0 && symtype.isObjectType() &&
+ qual.type.isStable())
+ symtype = Type.singleType(qual.type, sym);
+ return copy.Select(tree, qual, name)
+ .setSymbol(sym).setType(symtype);
+ }
+ }
+
+ /** Attribute a pattern matching expression where `pattpe' is the
+ * expected type of the patterns and `pt' is the expected type of the
+ * results.
+ */
+ Tree transformVisitor(Tree tree, Type pattpe, Type pt) {
+ //System.out.println("trans visitor with " + pt);//DEBUG
+ switch (tree) {
+ case Visitor(Tree.CaseDef[] cases):
+ Tree.CaseDef[] cases1 = cases;
+ for (int i = 0; i < cases.length; i++)
+ cases1[i] = transformCase(cases[i], pattpe, pt);
+ return copy.Visitor(tree, cases1)
+ .setType(Type.lub(Tree.typeOf(cases1)));
+ default:
+ throw new ApplicationError();
+ }
+ }
+
+ /** Attribute a case where `pattpe' is the expected type of the pattern
+ * and `pt' is the expected type of the result.
+ */
+ Tree.CaseDef transformCase(Tree.CaseDef tree, Type pattpe, Type pt) {
+ switch (tree) {
+ case CaseDef(Tree pat, Tree guard, Tree body):
+ pushContext(tree, context.owner, new Scope(context.scope));
+ Tree pat1 = transform(pat, PATTERNmode, pattpe);
+ Tree guard1 = guard;
+ if (guard != Tree.Empty)
+ guard1 = transform(guard, EXPRmode, definitions.BOOLEAN_TYPE);
+ Tree body1 = transform(body, EXPRmode, pt);
+ popContext();
+ return (Tree.CaseDef) copy.CaseDef(tree, pat1, guard1, body1)
+ .setType(body1.type);
+ default:
+ throw new ApplicationError();
+ }
+ }
+
+ Tree[] transformStatSeq(Tree[] stats, Symbol exprOwner) {
+ Tree[] stats1 = stats;
+ for (int i = 0; i < stats.length; i++) {
+ Tree stat = stats[i];
+ if (context.owner.isCompoundSym() && !TreeInfo.isDeclaration(stat)) {
+ error(stat.pos, "only declarations allowed here");
+ }
+ Tree stat1;
+ if (exprOwner.kind != NONE && !TreeInfo.isOwnerDefinition(stat)) {
+ pushContext(stat, exprOwner, context.scope);
+ if (TreeInfo.isDefinition(stat)) stat1 = transform(stat);
+ else stat1 = transform(stat, EXPRmode);
+ popContext();
+ } else {
+ if (TreeInfo.isDefinition(stat)) stat1 = transform(stat);
+ else stat1 = transform(stat, EXPRmode);
+ }
+ if (stat1 != stat && stats1 == stats) {
+ stats1 = new Tree[stats.length];
+ System.arraycopy(stats, 0, stats1, 0, i);
+ }
+ stats1[i] = stat1;
+ }
+ return stats1;
+ }
+
+ /** Attribute a sequence of constructor invocations.
+ */
+ Tree[] transformConstrInvocations(int pos, Tree[] constrs,
+ boolean delayArgs, Type pt) {
+ for (int i = 0; i < constrs.length; i++) {
+ pushContext(constrs[i], context.owner, context.scope);
+ context.delayArgs = delayArgs;
+ constrs[i] = transform(constrs[i], CONSTRmode, pt);
+ if (constrs[i].hasSymbol())
+ constrs[i].symbol().initialize();//to detect cycles
+ popContext();
+ }
+ return constrs;
+ }
+
+ /** Attribute a template
+ */
+ public Tree.Template transformTemplate(Tree.Template templ, Symbol owner) {
+ //System.out.println("transforming " + owner);//DEBUG
+ //System.out.println(owner.info());//DEBUG
+ Tree[] parents1 = transformConstrInvocations(
+ templ.pos, templ.parents, false, Type.AnyType);
+ if (owner.kind != ERROR) {
+ validateParentClasses(templ.parents, owner.info().parents());
+ validateBaseTypes(owner);
+ }
+ pushContext(templ, owner, owner.members());
+ templ.setSymbol(gen.localDummy(templ.pos, owner));
+ Tree[] body1 = transformStatSeq(templ.body, templ.symbol());
+ checkAllOverrides(owner);
+ popContext();
+ if (owner.isTrait()) {
+ for (int i = 0; i < templ.parents.length; i++)
+ checkTrait(templ.parents[i], owner);
+ for (int i = 0; i < templ.body.length; i++)
+ checkPureDef(templ.body[i], owner);
+ }
+ Tree.Template templ1 = copy.Template(templ, parents1, body1);
+ templ1.setType(owner.type());
+ return templ1;
+ }
+
+ public Tree transformApply(Tree tree, Tree fn, Tree[] args) {
+ Tree fn1;
+ int argMode;
+ if ((mode & (EXPRmode | CONSTRmode)) != 0) {
+ fn1 = transform(fn, mode | FUNmode, Type.AnyType);
+ argMode = EXPRmode;
+ } else {
+ assert (mode & PATTERNmode) != 0;
+ fn1 = transform(fn, mode | FUNmode, pt);
+ argMode = PATTERNmode;
+ }
+
+ // handle the case of application of match to a visitor specially
+ if (args.length == 1 && args[0] instanceof Visitor) {
+ Type pattp = matchQualType(fn1);
+ if (pattp == Type.ErrorType) {
+ return tree.setType(Type.ErrorType);
+ } else if (pattp != Type.NoType) {
+ Tree fn2 = desugarize.postMatch(fn1, context.enclClass.owner);
+ Tree arg1 = transformVisitor(args[0], pattp, pt);
+ return copy.Apply(tree, fn2, new Tree[]{arg1})
+ .setType(arg1.type);
+ }
+ }
+
+ // return prematurely if delayArgs is true and no type arguments
+ // need to be inferred.
+ if (context.delayArgs) {
+ switch (fn1.type) {
+ case MethodType(_, Type restp):
+ return tree.setType(restp);
+ }
+ }
+
+ // type arguments with formals as prototypes if they exist.
+ fn1.type = infer.freshInstance(fn1.type);
+ Type[] argtypes = transformArgs(
+ tree.pos, fn1.symbol(), Symbol.EMPTY_ARRAY, fn1.type, argMode, args, pt);
+
+ // propagate errors in arguments
+ if (argtypes == null) {
+ return tree.setType(Type.ErrorType);
+ }
+ for (int i = 0; i < argtypes.length; i++) {
+ if (argtypes[i] == Type.ErrorType) {
+ return tree.setType(Type.ErrorType);
+ }
+ }
+
+ // resolve overloading
+ switch (fn1.type) {
+ case OverloadedType(Symbol[] alts, Type[] alttypes):
+ try {
+ infer.methodAlternative(fn1, alts, alttypes, argtypes, pt);
+ } catch (Type.Error ex) {
+ error(tree, ex.msg);
+ }
+ }
+
+ switch (fn1.type) {
+ case PolyType(Symbol[] tparams, Type restp):
+ // if method is polymorphic,
+ // infer instance, and adapt arguments to instantiated formals
+ try {
+ fn1 = infer.methodInstance(fn1, tparams, restp, argtypes);
+ } catch (Type.Error ex) {
+ error(tree, ex.msg);
+ }
+ switch (fn1.type) {
+ case MethodType(Symbol[] params, Type restp1):
+ for (int i = 0; i < args.length; i++) {
+ args[i] = adapt(args[i], argMode, params[i].type());
+ }
+ return copy.Apply(tree, fn1, args)
+ .setType(restp1);
+ }
+ break;
+ case MethodType(Symbol[] params, Type restp):
+ // if method is monomorphic,
+ // check that it can be applied to arguments.
+ if (infer.isApplicable(fn1.type, argtypes, Type.AnyType)) {
+ return copy.Apply(tree, fn1, args)
+ .setType(restp);
+ }
+ }
+
+ if (fn1.type == Type.ErrorType)
+ return tree.setType(Type.ErrorType);
+
+ new TextTreePrinter().print(tree).println().end();//debug
+ return error(tree,
+ infer.applyErrorMsg(
+ "", fn1, " cannot be applied to ", argtypes, pt));
+
+ }
+
+ /** Attribute an argument list.
+ * @param pos Position for error reporting
+ * @param meth The symbol of the called method, or `null' if none exists.
+ * @param tparams The type parameters that need to be instantiated
+ * @param methtype The method's type w/o type parameters
+ * @param argMode The argument mode (either EXPRmode or PATTERNmode)
+ * @param args The actual arguments
+ * @param pt The proto-resulttype.
+ * @return The vector of instantiated argument types, or null if error.
+ */
+ Type[] transformArgs(int pos, Symbol meth, Symbol[] tparams, Type methtype,
+ int argMode, Tree[] args, Type pt) {
+ //System.out.println("trans args " + meth + ArrayApply.toString(tparams) + ":" + methtype + "," + pt);//DEBUG
+ Type[] argtypes = new Type[args.length];
+ switch (methtype) {
+ case MethodType(Symbol[] params, Type restp):
+ if (params.length != args.length) {
+ error(pos, "wrong number of arguments" +
+ (meth == null ? "" : " for " + meth));
+ return null;
+ }
+ if (tparams.length == 0) {
+ for (int i = 0; i < args.length; i++) {
+ args[i] = transform(args[i], argMode, params[i].type());
+ argtypes[i] = args[i].type;
+ }
+ } else {
+ // targs: the type arguments inferred from the prototype
+ Type[] targs = infer.protoTypeArgs(tparams, restp, pt, params);
+
+ // argpts: prototypes for arguments
+ Type[] argpts = new Type[params.length];
+ for (int i = 0; i < params.length; i++)
+ argpts[i] = params[i].type().subst(tparams, targs);
+
+ // transform arguments with [targs/tparams]params.type as prototypes
+ for (int i = 0; i < args.length; i++)
+ args[i] = transform(
+ args[i], argMode | POLYmode,
+ params[i].type().subst(tparams, targs));
+
+ // targs1: same as targs except that every AnyType is mapped to
+ // formal parameter type.
+ Type[] targs1 = new Type[targs.length];
+ for (int i = 0; i < targs.length; i++)
+ targs1[i] = (targs[i] != Type.AnyType) ? targs[i]
+ : tparams[i].type();
+
+ for (int i = 0; i < args.length; i++) {
+ argtypes[i] = args[i].type;
+ switch (argtypes[i]) {
+ case PolyType(Symbol[] tparams1, Type restype1):
+ argtypes[i] = infer.argumentTypeInstance(
+ tparams1, restype1,
+ params[i].type().subst(tparams, targs1),
+ argpts[i]);
+ }
+ }
+ }
+ return argtypes;
+
+ case PolyType(Symbol[] tparams1, Type restp):
+ Symbol[] tparams2;
+ if (tparams.length == 0) tparams2 = tparams1;
+ else {
+ tparams2 = new Symbol[tparams.length + tparams1.length];
+ System.arraycopy(tparams, 0, tparams2, 0, tparams.length);
+ System.arraycopy(tparams1, 0, tparams2, tparams.length, tparams1.length);
+ }
+ return transformArgs(pos, meth, tparams2, restp, argMode, args, pt);
+
+ default:
+ for (int i = 0; i < args.length; i++) {
+ args[i] = transform(args[i], argMode, Type.AnyType);
+ argtypes[i] = args[i].type;
+ }
+ }
+ return argtypes;
+ }
+
+ /** Atribute an expression or pattern with prototype `pt'.
+ * Check that expression's type conforms to `pt'.
+ * Resolve overloading and apply parameterless functions.
+ * Insert `apply' function if needed.
+ */
+ Tree transform(Tree tree, int mode, Type pt) {
+ //new TextTreePrinter().print("transforming ").print(tree).println().end();//DEBUG
+ int savedMode = this.mode;
+ Type savedPt = this.pt;
+ this.mode = mode;
+ this.pt = pt;
+ Tree tree1 = adapt(transform(tree), mode, pt);
+ this.mode = savedMode;
+ this.pt = savedPt;
+ return tree1;
+ }
+
+ Tree adapt(Tree tree, int mode, Type pt) {
+ //new TextTreePrinter().print(tree).print(" adapt " + pt).println().end();//DEBUG
+ switch (tree.type) {
+ case OverloadedType(Symbol[] alts, Type[] alttypes):
+ // resolve overloading
+ if ((mode & FUNmode) == 0) {
+ try {
+ infer.exprAlternative(tree, alts, alttypes, pt);
+ } catch (Type.Error ex) {
+ error(tree, ex.msg);
+ }
+ switch (tree.type) {
+ case OverloadedType(_, _):
+ // overload resolution failed bcs no alternative matched prototype.
+ typeError(tree.pos, tree.type, pt);
+ tree.setSymbol(Symbol.ERROR).setType(Type.ErrorType);
+ break;
+ default:
+ return adapt(tree, mode, pt);
+ }
+ }
+ break;
+
+ case PolyType(Symbol[] tparams, Type restp):
+ // apply parameterless functions
+ // instantiate polymorphic expressions
+ if (tparams.length == 0) {
+ return adapt(tree.setType(restp), mode, pt);
+ } else if ((mode & (FUNmode | POLYmode)) == 0) {
+ try {
+ tree = infer.exprInstance(tree, tparams, restp, pt);
+ } catch (Type.Error ex) {
+ error(tree, ex.msg);
+ }
+ return adapt(tree, mode, pt);
+ } else if ((mode & EXPRmode) != 0) {
+ // will be instantiated later
+ return tree;
+ }
+ break;
+
+ case MethodType(_, _):
+ // convert unapplied methods to functions.
+ if ((mode & (EXPRmode | FUNmode)) == EXPRmode &&
+ infer.isCompatible(tree.type, pt)) {
+ checkEtaExpandable(tree.pos, tree.type);
+ return transform(desugarize.etaExpand(tree, tree.type), mode, pt);
+ } else if ((mode & (CONSTRmode | FUNmode)) == CONSTRmode) {
+ return error(tree, "missing arguments for class constructor");
+ }
+ }
+ if ((mode & FUNmode) != 0) {
+ if ((mode & PATTERNmode) != 0) {
+ // set type to instantiated case class constructor
+ if (tree.type == Type.ErrorType) return tree;
+ Symbol clazz = tree.symbol().constructorClass();
+ if (!clazz.isCaseClass())
+ error(tree, clazz + " is not a case class");
+ tree.type = clazz.constructor().type();
+ switch (tree.type) {
+ case PolyType(Symbol[] tparams, Type restp):
+ try {
+ infer.constructorInstance(tree, tparams, restp, pt);
+ } catch (Type.Error ex) {
+ if (pt != Type.ErrorType) error(tree.pos, ex.msg);
+ tree.setType(Type.ErrorType);
+ }
+ }
+ return tree;
+ } else if ((mode & EXPRmode) != 0 && tree.type.isObjectType()) {
+ // insert apply method
+ Symbol applyMeth = tree.type.lookup(Names.apply);
+ if (applyMeth != Symbol.NONE && isAccessible(applyMeth, tree)) {
+ applyMeth.flags |= (ACCESSED | SELECTOR);
+ tree = make.Select(tree.pos, tree, Names.apply)
+ .setSymbol(applyMeth)
+ .setType(tree.type.memberType(applyMeth));
+ return adapt(tree, mode, pt);
+ }
+ }
+ } else if ((mode & (QUALmode | EXPRmode)) == EXPRmode) {
+ // check that packages and static modules are not used as values
+ Symbol sym = tree.symbol();
+ if (sym != null && sym.kind != ERROR && !sym.isValue() && tree.isTerm()) {
+ new TextTreePrinter().print(tree).println().end();//debug
+ error(tree.pos, tree.symbol() + " is not a value");
+ }
+ }
+
+ // check type against prototype
+ return tree.setType(checkType(tree.pos, tree.type, pt));
+ }
+
+ /** Transform expression or type with a given mode.
+ */
+ public Tree transform(Tree tree, int mode) {
+ if ((mode & TYPEmode) == 0)
+ return transform(tree, mode, Type.AnyType);
+
+ int savedMode = this.mode;
+ this.mode = mode;
+ Tree tree1 = transform(tree);
+ this.mode = savedMode;
+
+ Symbol sym = tree1.symbol();
+ if ((mode & FUNmode) == 0 && sym != null && sym.typeParams().length != 0)
+ return error(tree, sym + " takes type parameters.");
+ else
+ return tree1;
+ }
+
+ Tree[] transform(Tree[] trees, int mode) {
+ for (int i = 0; i < trees.length; i++)
+ trees[i] = transform(trees[i], mode);
+ return trees;
+ }
+
+ /** The main attribution function
+ */
+ public Tree transform(Tree tree) {
+ Symbol sym = tree.symbol();
+ if (sym != null && !sym.isInitialized()) sym.initialize();
+ if (global.debug && TreeInfo.isDefinition(tree))
+ System.out.println("transforming " + sym);
+ try {
+ switch (tree) {
+
+ case Bad():
+ tree.setType(Type.ErrorType);
+ return tree;
+
+ case Empty:
+ tree.type = Type.NoType;
+ return tree;
+
+ case PackageDef(Tree pkg, Tree.Template templ):
+ switch (templ) {
+ case Template(Tree[] parents, Tree[] body):
+ Symbol pkgSym = pkg.symbol();
+ if (pkgSym != null && pkgSym.isPackage()) {
+ pushContext(templ, pkgSym, pkgSym.members());
+ Tree[] body1 = transform(body);
+ popContext();
+ Tree.Template templ1 = copy.Template(templ, parents, body1);
+ templ1.setType(Type.NoType).setSymbol(Symbol.NONE);
+ return copy.PackageDef(tree, pkg, templ1)
+ .setType(definitions.UNIT_TYPE);
+ }
+ }
+ return tree.setType(Type.ErrorType);
+
+ case ClassDef(int mods, Name name, Tree.TypeDef[] tparams, Tree.ValDef[][] vparams, Tree tpe, Tree.Template templ):
+ pushContext(tree, sym.constructor(), new Scope(context.scope));
+ reenterParams(tparams);
+ reenterParams(vparams);
+ Tree.TypeDef[] tparams1 = transform(tparams);
+ Tree.ValDef[][] vparams1 = transform(vparams);
+ Tree tpe1 = transform(tpe);
+ Tree.Template templ1 = transformTemplate(templ, sym);
+ popContext();
+ return copy.ClassDef(tree, mods, name, tparams1, vparams1, tpe1, templ1)
+ .setType(definitions.UNIT_TYPE);
+
+ case ModuleDef(int mods, Name name, Tree tpe, Tree.Template templ):
+ Tree tpe1 = transform(tpe, TYPEmode);
+ Tree.Template templ1 = transformTemplate(templ, sym.moduleClass());
+ return copy.ModuleDef(tree, mods, name, tpe1, templ1)
+ .setType(definitions.UNIT_TYPE);
+
+ case ValDef(int mods, Name name, Tree tpe, Tree rhs):
+ Tree tpe1 = transform(tpe, TYPEmode);
+ Tree rhs1 = rhs;
+ if (tpe1 == Tree.Empty) {
+ tpe1 = gen.mkType(rhs1.pos, rhs.type);
+ // rhs already attributed by defineSym in this case
+ } else if (rhs != Tree.Empty) {
+ rhs1 = transform(rhs1, EXPRmode, sym.type());
+ }
+ return copy.ValDef(tree, mods, name, tpe1, rhs1)
+ .setType(definitions.UNIT_TYPE);
+
+ case DefDef(int mods, Name name, Tree.TypeDef[] tparams, Tree.ValDef[][] vparams, Tree tpe, Tree rhs):
+ pushContext(tree, sym, new Scope(context.scope));
+ reenterParams(tparams);
+ reenterParams(vparams);
+ Tree.TypeDef[] tparams1 = transform(tparams);
+ Tree.ValDef[][] vparams1 = transform(vparams);
+ Tree tpe1 = transform(tpe, TYPEmode);
+ Tree rhs1 = rhs;
+ if (tpe1 == Tree.Empty) {
+ tpe1 = gen.mkType(rhs1.pos, rhs1.type);
+ // rhs already attributed by defineSym in this case
+ } else if (rhs != Tree.Empty) {
+ rhs1 = transform(rhs, EXPRmode,
+ tpe1.type == Type.NoType ? Type.AnyType : tpe1.type);
+ }
+ popContext();
+ return copy.DefDef(tree, mods, name, tparams1, vparams1, tpe1, rhs1)
+ .setType(definitions.UNIT_TYPE);
+
+ case TypeDef(int mods, Name name, Tree.TypeDef[] tparams, Tree rhs):
+ pushContext(tree, sym, new Scope(context.scope));
+ reenterParams(tparams);
+ Tree.TypeDef[] tparams1 = transform(tparams);
+ Tree rhs1 = transform(rhs, TYPEmode);
+ popContext();
+ return copy.TypeDef(tree, mods, name, tparams1, rhs1)
+ .setType(definitions.UNIT_TYPE);
+
+ case Import(Tree expr, Name[] selectors):
+ context.imports = new ImportList(tree, context.scope, context.imports);
+ return Tree.Empty;
+
+ case Block(Tree[] stats):
+ pushContext(tree, context.owner, new Scope(context.scope));
+ int lastmode = mode;
+ Tree[] stats1 = desugarize.Statements(stats, true);
+ enterSyms(stats1);
+ context.imports = context.outer.imports;
+ for (int i = 0; i < stats1.length - 1; i++)
+ stats1[i] = transform(stats1[i], EXPRmode);
+ Type tp;
+ if (stats1.length > 0) {
+ stats1[stats1.length - 1] =
+ transform(stats1[stats1.length - 1], lastmode, pt);
+ tp = checkNoEscape(tree.pos, stats1[stats1.length - 1].type);
+ } else {
+ tp = definitions.UNIT_TYPE;
+ }
+ popContext();
+ return copy.Block(tree, stats1)
+ .setType(tp);
+
+ case Visitor(Tree.CaseDef[] cases):
+ return transform(desugarize.Visitor(tree));
+
+ case Assign(Apply(Tree funarray, Tree[] vparam), Tree rhs):
+ return transform(desugarize.Update(tree));
+
+ case Assign(Tree lhs, Tree rhs):
+ Tree lhs1 = transform(lhs, EXPRmode);
+ Symbol varsym = lhs1.symbol();
+ if (varsym != null && (varsym.flags & ACCESSOR) != 0) {
+ return transform(desugarize.Assign(tree.pos, lhs, rhs));
+ } else if (varsym == null || (varsym.flags & MUTABLE) == 0) {
+ return error(tree, "assignment to non-variable");
+ } else {
+ Tree rhs1 = transform(rhs, EXPRmode, lhs1.type);
+ return copy.Assign(tree, lhs1, rhs1)
+ .setType(definitions.UNIT_TYPE);
+ }
+
+ case If(Tree cond, Tree thenp, Tree elsep):
+ Tree cond1 = transform(cond, EXPRmode, definitions.BOOLEAN_TYPE);
+ if (elsep == Tree.Empty) {
+ Tree thenp1 =
+ transform(thenp, EXPRmode, definitions.UNIT_TYPE);
+ Tree elsep1 = make.Block(tree.pos, Tree.EMPTY_ARRAY)
+ .setType(definitions.UNIT_TYPE);
+ return copy.If(tree, cond1, thenp1, elsep1)
+ .setType(definitions.UNIT_TYPE);
+ } else {
+ Tree thenp1 = transform(thenp, EXPRmode, pt);
+ Tree elsep1 = transform(elsep, EXPRmode, pt);
+ return copy.If(tree, cond1, thenp1, elsep1)
+ .setType(Type.lub(new Type[]{thenp1.type, elsep1.type}));
+ }
+
+ case New(Tree.Template templ):
+ switch (templ) {
+ case Template(Tree[] parents, Tree[] body):
+ if (parents.length == 1 && body.length == 0) {
+ Tree parent1 = transform(parents[0], CONSTRmode, pt);
+ Tree.Template templ1 = (Tree.Template)
+ copy.Template(templ, new Tree[]{parent1}, body)
+ .setType(parent1.type).setSymbol(Symbol.NONE);
+ Type owntype = parent1.type;
+ if ((owntype.symbol().constructor().flags &
+ ABSTRACTCLASS) != 0) {
+ error(tree.pos, owntype.symbol() +
+ " is abstract; cannot be instantiated");
+ }
+ return copy.New(tree, templ1)
+ .setType(owntype);
+ } else {
+ pushContext(tree, context.owner, new Scope(context.scope));
+ Tree cd = make.ClassDef(
+ templ.pos,
+ 0,
+ Names.ANON_CLASS_NAME.toTypeName(),
+ Tree.ExtTypeDef.EMPTY_ARRAY,
+ Tree.ExtValDef.EMPTY_ARRAY_ARRAY,
+ Tree.Empty,
+ templ);
+ enterSym(cd);
+ cd = transform(cd);
+ Symbol clazz = cd.symbol();
+ if (clazz.kind != CLASS)
+ return Tree.Bad().setType(Type.ErrorType);
+
+ // compute template's type with new refinement scope.
+ Type[] parentTypes = clazz.info().parents();
+ Scope refinement = new Scope();
+ Type base = Type.compoundType(parentTypes, Scope.EMPTY);
+ Type tp = Type.compoundType(
+ parentTypes, refinement, clazz);
+ Scope.SymbolIterator it = clazz.members().iterator();
+ while (it.hasNext()) {
+ Symbol sym1 = it.next();
+ if (base.lookupNonPrivate(sym1.name).kind != NONE &&
+ !base.memberType(sym1).isSameAs(sym1.type()))
+ refinement.enter(sym1);
+ }
+ if (refinement.elems == Scope.Entry.NONE &&
+ parentTypes.length == 1)
+ tp = parentTypes[0];
+ else
+ tp = checkNoEscape(tree.pos, tp);
+
+ Tree alloc =
+ gen.Typed(
+ gen.New(
+ gen.mkRef(tree.pos,
+ Type.localThisType, clazz.constructor())),
+ tp);
+ popContext();
+ return make.Block(tree.pos, new Tree[]{cd, alloc})
+ .setType(tp);
+ }
+ default:
+ throw new ApplicationError();
+ }
+
+ case Typed(Tree expr, Tree tpe):
+ Tree tpe1 = transform(tpe, TYPEmode);
+ Tree expr1 = transform(expr, EXPRmode, tpe1.type);
+ return copy.Typed(tree, expr1, tpe1)
+ .setType(tpe1.type);
+
+ case Tuple(Tree[] trees):
+ Tree tree1 = transform(desugarize.Tuple(tree), mode, pt);
+ if (trees.length > 0 && (mode & EXPRmode) != 0)
+ tree1 = desugarize.postTuple(tree1);
+ return tree1;
+
+ case Function(Tree.ValDef[] vparams, Tree body):
+ pushContext(tree, context.owner, new Scope(context.scope));
+ Type restype = desugarize.preFunction(vparams, pt);
+ enterParams(vparams);
+ Tree body1 = transform(body, EXPRmode, restype);
+ if (!infer.isFullyDefined(restype)) restype = body1.type;
+ popContext();
+ Tree tree1 = copy.Function(tree, vparams, body1);
+ Tree tree2 = transform(desugarize.Function(tree1, restype));
+ return desugarize.postFunction(tree2);
+
+ case TypeApply(Tree fn, Tree[] args):
+ Tree fn1 = transform(fn, EXPRmode | FUNmode, Type.AnyType);
+ Tree[] args1 = transform(args, TYPEmode);
+ Type[] argtypes = Tree.typeOf(args1);
+
+ // resolve overloading
+ switch (fn1.type) {
+ case OverloadedType(Symbol[] alts, Type[] alttypes):
+ try {
+ infer.polyAlternative(fn1, alts, alttypes, args.length);
+ } catch (Type.Error ex) {
+ error(tree, ex.msg);
+ }
+ }
+
+ // match against arguments
+ switch (fn1.type) {
+ case PolyType(Symbol[] tparams, Type restp):
+ if (tparams.length == argtypes.length) {
+ int i = 0;
+ while (i < tparams.length &&
+ (context.delayArgs ||
+ argtypes[i].isSubType(
+ tparams[i].info().subst(tparams, argtypes))))
+ i++;
+ if (i == tparams.length) {
+ return copy.TypeApply(tree, fn1, args1)
+ .setType(restp.subst(tparams, argtypes));
+ }
+ }
+ break;
+ case ErrorType:
+ return tree.setType(Type.ErrorType);
+ }
+ return error(tree,
+ infer.toString(fn1.symbol(), fn1.type) +
+ " cannot be applied to " +
+ ArrayApply.toString(argtypes, "[", ",", "]"));
+
+ case Apply(Tree fn, Tree[] args):
+ Tree tree1 = transformApply(tree, fn, args);
+
+ // handle the case of a case method call specially.
+ Symbol fsym = TreeInfo.methSymbol(tree1);
+ if ((mode & (EXPRmode | FUNmode)) == EXPRmode &&
+ fsym != null && (fsym.flags & CASE) != 0) {
+ Symbol constr = fsym.type().resultType().symbol().constructor();
+ Template templ = make.Template(
+ tree1.pos,
+ new Tree[]{desugarize.toConstructor(tree1, constr)},
+ Tree.EMPTY_ARRAY);
+ templ.setSymbol(Symbol.NONE).setType(tree1.type);
+ return adapt(
+ make.New(tree1.pos, templ).setType(tree1.type), mode, pt);
+ } else {
+ return tree1;
+ }
+
+ case Super(Tree tpe):
+ Symbol enclClazz = context.enclClass.owner;
+ if (enclClazz != null) {
+ // we are in a class or module
+ Tree tpe1 = transform(tpe, TYPEmode); // ignored for now.
+ switch (enclClazz.info()) {
+ case CompoundType(Type[] parents, _):
+ return copy.Super(tree, tpe1)
+ .setType(Type.compoundType(parents, Scope.EMPTY));
+ case ErrorType:
+ return tree.setType(Type.ErrorType);
+ default:
+ throw new ApplicationError();
+ }
+ } else {
+ return error(tree,
+ "super can be used only in a class, module, or template");
+ }
+
+ case This(Tree qual):
+ if (qual == Tree.Empty) {
+ Symbol clazz = context.enclClass.owner;
+ if (clazz != null) { // we are in a class or module
+ return make.This(
+ tree.pos,
+ make.Ident(tree.pos, clazz.name)
+ .setSymbol(clazz).setType(clazz.type()))
+ .setType(clazz.thisType());
+ } else {
+ return error(
+ tree, tree +
+ " can be used only in a class, module, or template");
+ }
+ } else {
+ Tree qual1 = transform(qual, TYPEmode | FUNmode);
+ Symbol clazz = qual1.symbol();
+ if (clazz.kind == CLASS) {
+ Context clazzContext = context.outerContext(clazz);
+ if (clazzContext != Context.NONE) {
+ return tree.setType(clazz.thisType());
+ } else {
+ return error(
+ qual, clazz.name + " is not an enclosing class");
+ }
+ } else {
+ return error(qual, "class identifier expected");
+ }
+ }
+
+ case Select(Tree qual, Name name):
+ Tree qual1 = transform(qual, EXPRmode | POLYmode | QUALmode);
+ if (name.isTypeName()) qual1 = checkStable(qual1);
+ return transformSelect(
+ tree,
+ adapt(qual1, EXPRmode | POLYmode | QUALmode, Type.AnyType),
+ name);
+
+ case Ident(Name name):
+ if (mode == PATTERNmode && name.isVariable()) {
+ //System.out.println("pat var " + name + ":" + pt);//DEBUG
+ Symbol vble = new TermSymbol(
+ tree.pos, name, context.owner, 0).setType(pt);
+ if (name != Names.WILDCARD) enterInScope(vble);
+ return tree.setSymbol(vble).setType(pt);
+ } else {
+ return transformIdent(tree, name);
+ }
+
+ case Literal(Object value):
+ return tree.setType(definitions.getType(value2TypeName(value)));
+
+ case SingletonType(Tree ref):
+ Tree ref1 = transform(ref, EXPRmode, Type.AnyType);
+ return copy.SingletonType(tree, ref1)
+ .setType(checkObjectType(tree.pos, ref1.type));
+
+ case SelectFromType(Tree qual, Name name):
+ Tree qual1 = transform(qual, TYPEmode);
+ return transformSelect(tree, qual1, name);
+
+ case CompoundType(Tree[] parents, Tree[] refinements):
+ Tree[] parents1 = transform(parents, TYPEmode);
+ Type[] ptypes = Tree.typeOf(parents);
+ Scope members = new Scope();
+ Type self = Type.compoundType(ptypes, members);
+ Symbol clazz = self.symbol();
+ validateBaseTypes(clazz);
+ pushContext(tree, clazz, members);
+ for (int i = 0; i < refinements.length; i++) {
+ enterSym(refinements[i]).flags |= OVERRIDE;
+ }
+ Tree[] refinements1 = transformStatSeq(refinements, Symbol.NONE);
+ checkAllOverrides(clazz);
+ popContext();
+ return copy.CompoundType(tree, parents1, refinements1)
+ .setType(self);
+
+ case AppliedType(Tree tpe, Tree[] args):
+ Tree tpe1 = transform(tpe, TYPEmode | FUNmode);
+ Tree[] args1 = transform(args, TYPEmode);
+ Type[] argtypes = Tree.typeOf(args);
+ Symbol clazz = tpe1.type.unalias().symbol();
+ Symbol[] tparams = clazz.typeParams();
+ if (tpe1.type != Type.ErrorType) {
+ if (tparams.length != args.length) {
+ if (tparams.length == 0)
+ return error(tree, tpe1.type +
+ " does not take type parameters");
+ else
+ return error(tree,
+ "wrong number of type arguments for " +
+ tpe1.type);
+ } else {
+ try {
+ if (!context.delayArgs)
+ infer.checkBounds(tparams, argtypes, "");
+ } catch (Type.Error ex) {
+ return error(tree, ex.msg);
+ }
+ }
+ return copy.AppliedType(tree, tpe1, args1)
+ .setType(Type.appliedType(tpe1.type, argtypes));
+ } else {
+ return tpe1;
+ }
+
+ case CovariantType(Tree tpe):
+ Tree tpe1 = transform(tpe, TYPEmode);
+ return copy.CovariantType(tree, tpe1)
+ .setType(Type.covarType(tpe1.type));
+
+ case FunType(_, _):
+ return transform(desugarize.FunType(tree));
+
+ case TupleType(Tree[] types):
+ Tree tree1 = desugarize.mkTupleType(tree.pos, types);
+ return transform(desugarize.mkTupleType(tree.pos, types));
+
+ default:
+ throw new ApplicationError("illegal tree: " + tree);
+ }
+ } catch (Type.Error ex) {
+ if (ex instanceof CyclicReference) {
+ if (global.debug) ex.printStackTrace();//DEBUG
+ CyclicReference cyc = (CyclicReference) ex;
+ if (cyc.info instanceof LazyTreeType) {
+ switch (((LazyTreeType) cyc.info).tree) {
+ case ValDef(_, _, _, _):
+ return error(tree, "recursive " + cyc.sym + " needs type");
+ case DefDef(_, _, _, _, _, _):
+ return error(tree, "recursive " + cyc.sym + " needs result type");
+ }
+ }
+ }
+ return error(tree, ex.msg);
+ }
+ }
+
+// Contexts -------------------------------------------------------------------
+
+ /** Push new context associated with given tree, owner, and scope on stack.
+ * Fields `imports' and, possibly, `enclClass' are inherited from parent.
+ */
+ void pushContext(Tree tree, Symbol owner, Scope scope) {
+ context = new Context(tree, owner, scope, context);
+ }
+
+ /** Pop context from stack.
+ */
+ void popContext() {
+ context = context.outer;
+ }
+
+// Lazy Types ------------------------------------------------------------------
+
+ /** A lazy type which, when forced returns the type of a symbol defined
+ * in `tree'.
+ */
+ class LazyTreeType extends Type.LazyType {
+ Tree tree;
+ Unit u;
+ Infer i;
+ Context c;
+
+ LazyTreeType(Tree tree) {
+ this.tree = tree;
+ this.u = unit;
+ this.i = infer;
+ this.c = context;
+ }
+ public void complete(Symbol sym) {
+ //if (sym.isConstructor()) sym.constructorClass().initialize();
+ //else if (sym.isModule()) sym.moduleClass().initialize();
+ defineSym(tree, u, i, c);
+ }
+ }
+
+ /** A lazy type for case constructor methods (whose name is a term name)
+ * which sets the method's type to the class constructor type.
+ */
+ class LazyConstrMethodType extends LazyTreeType {
+ LazyConstrMethodType(Tree tree) {
+ super(tree);
+ }
+ public void complete(Symbol sym) {
+ sym.setInfo(tree.symbol().constructor().type());
+ }
+ }
+}
+