From 3a593c580c9a23b3654ea3391fb22afa85db0697 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 4 Jun 2003 14:53:23 +0000 Subject: *** empty log message *** --- sources/scalac/CompilerCommand.java | 5 + sources/scalac/Global.java | 2 + sources/scalac/ast/Tree.java.tmpl | 44 +-- sources/scalac/ast/TreeInfo.java | 13 + sources/scalac/ast/printer/TextTreePrinter.java | 13 +- sources/scalac/symtab/Symbol.java | 12 +- sources/scalac/symtab/Type.java | 18 +- sources/scalac/transformer/Erasure.java | 2 +- sources/scalac/typechecker/Analyzer.java | 480 ++++++++++++------------ sources/scalac/typechecker/DeSugarize.java | 2 +- sources/scalac/typechecker/Infer.java | 4 +- sources/scalac/util/Name.java | 8 +- sources/scalac/util/Names.java | 2 + 13 files changed, 317 insertions(+), 288 deletions(-) (limited to 'sources') diff --git a/sources/scalac/CompilerCommand.java b/sources/scalac/CompilerCommand.java index 6aaa94a894..ed2b4d2a29 100644 --- a/sources/scalac/CompilerCommand.java +++ b/sources/scalac/CompilerCommand.java @@ -36,6 +36,7 @@ public class CompilerCommand extends CommandParser { public final BooleanOptionParser nowarn; public final BooleanOptionParser verbose; public final BooleanOptionParser debug; + public final BooleanOptionParser explaintypes; public final BooleanOptionParser uniqid; public final BooleanOptionParser types; public final BooleanOptionParser prompt; @@ -88,6 +89,10 @@ public class CompilerCommand extends CommandParser { "debug", "Output debugging messages", false), + this.explaintypes = new BooleanOptionParser(this, + "explaintypes", "Explain type errors in more detail", + false), + this.uniqid = new BooleanOptionParser(this, "uniqid", "Print identifiers with unique names (debugging option)", false), diff --git a/sources/scalac/Global.java b/sources/scalac/Global.java index cabac41a66..c74421f6a0 100644 --- a/sources/scalac/Global.java +++ b/sources/scalac/Global.java @@ -36,6 +36,7 @@ public class Global { public final boolean nopredefs; //public final boolean optimize; public final boolean debug; + public final boolean explaintypes; public final boolean uniqid; public final boolean printtypes; @@ -145,6 +146,7 @@ public class Global { //this.optimize = args.optimize.optimize; this.debug = args.debug.value; this.uniqid = args.uniqid.value; + this.explaintypes = args.explaintypes.value; this.printtypes = args.types.value; this.printtokens = args.print.tokens; this.classPath = args.classpath(); diff --git a/sources/scalac/ast/Tree.java.tmpl b/sources/scalac/ast/Tree.java.tmpl index 65b81b905b..eaf9b7647c 100644 --- a/sources/scalac/ast/Tree.java.tmpl +++ b/sources/scalac/ast/Tree.java.tmpl @@ -14,6 +14,8 @@ import scalac.symtab.Symbol; import scalac.symtab.Type; import scalac.util.Debug; import scalac.util.Position; +import java.io.StringWriter; +import scalac.ast.printer.TextTreePrinter; {#Imports#} public class Tree { @@ -115,45 +117,9 @@ public class Tree { * phase needs support for Apply, so this case got added */ public String toString() { - switch (this) { - case This(Tree qual): - return (qual == Tree.Empty) ? "this" : qual + ".this"; - case Select(Tree qual, Name name): - return qual + "." + name; - case Ident(Name name): - return name.toString(); - case Typed(Tree expr, Tree type): - return "(" + expr + ": " + type + ")"; - case TypeApply(Tree fn, Tree[] args): - String res = fn + "["; - if ((args == null) || (args.length == 0)) - return res + "]"; - res += args[0].toString(); - for (int i = 1; i < args.length; i++) - res += ", " + args[i]; - return res + "]"; - case Apply(Tree fn, Tree[] args): - String res = fn + "("; - if ((args == null) || (args.length == 0)) - return res + ")"; - res += args[0].toString(); - for (int i = 1; i < args.length; i++) - res += ", " + args[i]; - return res + ")"; - case Literal(Object value): - if (value instanceof String) - return "\"" + value + "\""; - else - return value.toString(); - case Import(Tree expr, _): - return "import " + expr; - case Empty: - return ""; - case TypeTerm(): - return type().toString(); - default: - return super.toString(); - } + StringWriter out = new StringWriter(); + new TextTreePrinter(out).print(this).flush(); + return out.toString(); } //######################################################################## diff --git a/sources/scalac/ast/TreeInfo.java b/sources/scalac/ast/TreeInfo.java index f377468e08..052b6bd326 100644 --- a/sources/scalac/ast/TreeInfo.java +++ b/sources/scalac/ast/TreeInfo.java @@ -122,6 +122,8 @@ public class TreeInfo { } } + /** Is tree a variable pattern + */ public static boolean isVarPattern(Tree pat) { switch (pat) { case Ident(Name name): @@ -131,6 +133,17 @@ public class TreeInfo { } } + /** Is tree a this node which belongs to `enclClass'? + */ + public static boolean isSelf(Tree tree, Symbol enclClass) { + switch (tree) { + case This(Tree qual): + return qual.symbol() == enclClass; + default: + return false; + } + } + /** The method symbol of an application node, or Symbol.NONE, if none exists. */ public static Symbol methSymbol(Tree tree) { diff --git a/sources/scalac/ast/printer/TextTreePrinter.java b/sources/scalac/ast/printer/TextTreePrinter.java index 9bf0dbf700..6ed0e0d9b7 100644 --- a/sources/scalac/ast/printer/TextTreePrinter.java +++ b/sources/scalac/ast/printer/TextTreePrinter.java @@ -44,6 +44,15 @@ public class TextTreePrinter implements TreePrinter { this.out = new PrintWriter(stream); } + public TextTreePrinter(Writer stream) { + this(stream, false); + } + + public TextTreePrinter(Writer stream, boolean autoFlush) { + this.autoFlush = autoFlush; + this.out = new PrintWriter(stream); + } + public TextTreePrinter() { this(System.out); } @@ -728,9 +737,9 @@ public class TextTreePrinter implements TreePrinter { } protected void printBounds(Tree lobound, Tree hibound) { - if (lobound.toString() != "scala.All") + if (!"scala.All".equals(lobound.toString())) printOpt(TXT_SUPERTYPE, lobound, true); - if (hibound.toString() != "scala.Any") + if (!"scala.Any".equals(hibound.toString())) printOpt(TXT_SUBTYPE, hibound, true); } diff --git a/sources/scalac/symtab/Symbol.java b/sources/scalac/symtab/Symbol.java index c4f0c1a9c6..65184b2134 100644 --- a/sources/scalac/symtab/Symbol.java +++ b/sources/scalac/symtab/Symbol.java @@ -496,11 +496,17 @@ public abstract class Symbol implements Modifiers, Kinds { /** the current phase id, or the id after analysis, whichever is larger. */ - int currentPhaseId() { + static int currentPhaseId() { int id = Global.instance.currentPhase.id; return id < FIRST_ID ? FIRST_ID : id; } + public int definedPhaseId() { + TypeIntervalList i = infos; + while (i.prev != TypeIntervalList.EMPTY) i = i.prev; + return i.limit; + } + /** Is this symbol initialized? */ public final boolean isInitialized() { return (flags & INITIALIZED) != 0; @@ -869,6 +875,7 @@ public abstract class Symbol implements Modifiers, Kinds { return Symbol.NONE; } else { //System.out.println(this + ":" + this.type() + locationString() + " overrides? " + sym1 + sym1.type() + sym1.locationString()); //DEBUG + //System.out.println(owner.thisType());//DEBUG Type symtype = owner.thisType().memberType(this); //todo: try whether we can do: this.type(); instead @@ -1046,7 +1053,7 @@ public class TypeSymbol extends Symbol { if (kind == ALIAS) return info().symbol().closure(); int id = currentPhaseId(); if (closures.limit < id) { - if (id == FIRST_ID || changes(closureAt(id - 1))) { + if (id <= definedPhaseId() || changes(closureAt(id - 1))) { closures = new ClosureIntervalList(closures); closures.limit = id; computeClosure(); @@ -1090,6 +1097,7 @@ public class TypeSymbol extends Symbol { assert closures.closure != BAD_CLOSURE : this; closures.closure = BAD_CLOSURE; // to catch cycles. // todo: why can't we do: inclClosure(SymSet.EMPTY, this) ? + //System.out.println("computing closure of " + this);//DEBUG SymSet closureClassSet = inclClosure(SymSet.EMPTY, type().parents()); Symbol[] closureClasses = new Symbol[closureClassSet.size() + 1]; closureClasses[0] = this; diff --git a/sources/scalac/symtab/Type.java b/sources/scalac/symtab/Type.java index 4b5315c418..62db7526e9 100644 --- a/sources/scalac/symtab/Type.java +++ b/sources/scalac/symtab/Type.java @@ -15,7 +15,7 @@ import scalac.Global; public class Type implements Modifiers, Kinds, TypeTags { - public static boolean debugSwitch = false; + public static boolean explainSwitch = false; private static int indent = 0; public case ErrorType; // not used after analysis @@ -863,12 +863,14 @@ public class Type implements Modifiers, Kinds, TypeTags { for (int i = 0; i < baseparams.length; i++) { if (sym == baseparams[i]) return baseargs[i]; } + //System.out.println(sym + " " + basesym + " " + ArrayApply.toString(baseparams));//DEBUG break; case ErrorType: return ErrorType; } throw new ApplicationError( - this + " in " + ownclass + " cannot be instantiated from " + pre.widen()); + this + " in " + ownclass + " cannot be instantiated from " + pre.widen() + ); } else { return toInstance(sym, pre.baseType(clazz).prefix(), clazz.owner()); } @@ -1166,13 +1168,13 @@ public class Type implements Modifiers, Kinds, TypeTags { /** Is this type a subtype of that type? */ public boolean isSubType(Type that) { - if (debugSwitch) { + if (explainSwitch) { for (int i = 0; i < indent; i++) System.out.print(" "); System.out.println(this + " < " + that + "?"); indent++; } boolean result = isSubType0(that); - if (debugSwitch) { + if (explainSwitch) { indent--; for (int i = 0; i < indent; i++) System.out.print(" "); System.out.println(result); @@ -1393,13 +1395,13 @@ public class Type implements Modifiers, Kinds, TypeTags { /** Does this type implement symbol `sym1' with same or stronger type? */ public boolean specializes(Symbol sym1) { - if (debugSwitch) { + if (explainSwitch) { for (int i = 0; i < indent; i++) System.out.print(" "); System.out.println(this + " specializes " + sym1 + "?"); indent++; } boolean result = specializes0(sym1); - if (debugSwitch) { + if (explainSwitch) { indent--; for (int i = 0; i < indent; i++) System.out.print(" "); System.out.println(result); @@ -1428,13 +1430,13 @@ public class Type implements Modifiers, Kinds, TypeTags { /** Is this type the same as that type? */ public boolean isSameAs(Type that) { - if (debugSwitch) { + if (explainSwitch) { for (int i = 0; i < indent; i++) System.out.print(" "); System.out.println(this + " = " + that + "?"); indent++; } boolean result = isSameAs0(that); - if (debugSwitch) { + if (explainSwitch) { indent--; for (int i = 0; i < indent; i++) System.out.print(" "); System.out.println(result); diff --git a/sources/scalac/transformer/Erasure.java b/sources/scalac/transformer/Erasure.java index 1b06683d16..ac7b0d401f 100644 --- a/sources/scalac/transformer/Erasure.java +++ b/sources/scalac/transformer/Erasure.java @@ -298,7 +298,7 @@ public class Erasure extends Transformer implements Modifiers { if (c.isClass() && !c.isInterface()) { Type[] basetypes = c.parents(); - //System.out.println("trying " + c + " <= " + ArrayApply.toString(c.basetypes()));//DEBUG + //System.out.println("trying " + sym + ":" + sym.info() + " in " + c + " <= " + scalac.util.ArrayApply.toString(basetypes));//DEBUG for (int i = 0; i < basetypes.length; i++) { Symbol sym1 = sym.overriddenSymbol(basetypes[i]); diff --git a/sources/scalac/typechecker/Analyzer.java b/sources/scalac/typechecker/Analyzer.java index dbe7a6122b..eb9758b198 100644 --- a/sources/scalac/typechecker/Analyzer.java +++ b/sources/scalac/typechecker/Analyzer.java @@ -7,8 +7,11 @@ // $Id$ // todo: (0) propagate target type in cast. -// todo: (1) check that only stable defs override stable defs // todo: eliminate Typed nodes. +// todo: use SELECTOR flag to avoid access methods for privates +// todo: drop requirement that only abstract classes can have abstract +// type members. +// todo: use mangled name or drop. package scalac.typechecker; @@ -35,8 +38,6 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { this.desugarize = new DeSugarize(this, global); } - /** Phase variables, used and set in transformers; - */ private Unit unit; private Context context; private Type pt; @@ -46,7 +47,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { for (int i = 0; i < global.units.length; i++) { enterUnit(global.units[i]); } - super.apply(); + super.apply(); // this calls apply(u) for every unit `u'. int n = descr.newSources.size(); while (n > 0) { int l = global.units.length; @@ -101,7 +102,6 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { 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) { @@ -121,7 +121,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { static final int CONSTRmode = 0x004; static final int TYPEmode = 0x008; - static final int FUNmode = 0x10; // orthogonal to above. When set + 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 @@ -148,7 +148,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { return matchQualType(fn1); case Ident(_): if (fn.symbol() == definitions.OBJECT_TYPE.lookup(Names.match)) - return context.enclClass.owner.type(); + return context.enclClass.owner.typeOfThis(); break; } return fn.type == Type.ErrorType ? Type.ErrorType : Type.NoType; @@ -175,21 +175,20 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { } void explainTypes(Type found, Type required) { - if (global.debug) { - Type.debugSwitch = true; + if (global.explaintypes) { + Type.explainSwitch = true; found.isSubType(required); - Type.debugSwitch = false; + Type.explainSwitch = false; } } 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); + String msg = infer.typeErrorMsg("type mismatch", found, req); + Type foundResult = found.resultType(); + if (foundResult != found && infer.isCompatible(foundResult, req)) + msg = msg + + "\n possible cause: missing arguments for method or constructor"; + error(pos, msg); } void reportTypeError(int pos, Type.Error ex) { @@ -200,9 +199,10 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { switch (((LazyTreeType) cyc.info).tree) { case ValDef(_, _, Tree.Empty, _): error(pos, "recursive " + cyc.sym + " needs type"); - break; + return; case DefDef(_, _, _, _, Tree.Empty, _): error(pos, "recursive function " + cyc.sym.name + " needs result type"); + return; } } } @@ -218,6 +218,14 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { else return "value " + NameTransformer.decode(name); } + /** Check that `sym' accessible as a member of tree `site' in current context. + */ + void checkAccessible(int pos, Symbol sym, Tree site) { + if (!isAccessible(sym, site)) { + error(pos, sym + " cannot be accessed in " + site.type); + } + } + /** Is `sym' accessible as a member of tree `site' in current context? */ boolean isAccessible(Symbol sym, Tree site) { @@ -256,9 +264,10 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { /** 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. + * - `abstract' modifier only for classes + * - `override' modifier never for classes + * - def and `*' modifiers only in methods + * - declarations only in traits or abstract classes * - symbols with `override' modifier override some other symbol. */ void validate(Symbol sym) { @@ -272,7 +281,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { "\nit should be omitted for abstract members"); } if ((sym.flags & OVERRIDE) != 0 && sym.kind == CLASS) { - error(sym.pos, "`override' modifier ot allowed for classes"); + error(sym.pos, "`override' modifier not allowed for classes"); } if ((sym.flags & DEF) != 0 && sym.owner().isPrimaryConstructor()) { error(sym.pos, "`def' modifier not allowed for class parameters"); @@ -312,10 +321,9 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { * nested within definition of base class, or that occur within same * statement sequence. * - self-type of current class is a subtype of self-type of each parent class. - * - parent types do not refer to value parameters of class. + * - parent constructors do not refer to value parameters of class. */ void validateParentClasses(Tree[] constrs, Type[] parents, Type selfType) { - if (parents.length == 0 || !checkClassType(constrs[0].pos, parents[0])) return; for (int i = 0; i < parents.length; i++) { if (!checkClassType(constrs[i].pos, parents[i])) return; Symbol bsym = parents[i].symbol(); @@ -377,8 +385,10 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { } } - /** 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. + /** 1. Check that only traits are inherited several times (except if the + * inheriting instance is a compund type). + * 2. Check that later type instances in the base-type sequence + * of a class are subtypes of earlier type instances of the same trait. * 3. Check that case classes do not inherit from case classes. */ void validateBaseTypes(Symbol clazz) { @@ -406,15 +416,11 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { // if there are two different type instances of same class // check that second is a subtype of first. if (!seen[index].isSubType(tp)) { - if (clazz.isCompoundSym()) - error(clazz.pos, - "illegal combination;\n " + "compound type " + - " combines different type instances of " + - baseclazz + ":\n" + tp + " and " + seen[index]); - else - error(clazz.pos, "illegal inheritance;\n " + clazz + - " inherits different type instances of " + - baseclazz + ":\n" + tp + " and " + seen[index]); + String msg = (clazz.isCompoundSym()) + ? "illegal combination;\n compound type combines" + : "illegal inheritance;\n " + clazz + " inherits"; + error(clazz.pos, msg + " different type instances of " + + baseclazz + ":\n" + tp + " and " + seen[index]); } } // check that case classes do not inherit from case classes @@ -427,7 +433,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { } } - /** Check that type is eta-expandable (i.e. no `def' parameters) + /** Check that type is eta-expandable (i.e. no `def' or `*' parameters) */ void checkEtaExpandable(int pos, Type tp) { switch (tp) { @@ -465,12 +471,12 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { if ((sym.flags & LOCKED) != 0) { error(pos, "cyclic aliasing or subtyping involving " + sym); } else if (sym.kind == ALIAS || sym.kind == TYPE) { - assert (sym.flags & LOCKED) == 0; sym.flags |= LOCKED; checkNonCyclic( pos, pre.memberInfo(sym).subst(sym.typeParams(), args)); if (sym.kind == TYPE) - checkNonCyclic(pos, tp.loBound()); + checkNonCyclic( + pos, pre.memberLoBound(sym).subst(sym.typeParams(), args)); sym.flags &= ~LOCKED; } break; @@ -528,31 +534,28 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { error(tree.pos, clazz + " may contain only pure definitions"); } - /** Check that tree represents a pure definition. + /** Check that tree represents a pure constructor. + */ + void checkPureConstr(Tree tree, Symbol clazz) { + if (!TreeInfo.isPureConstr(tree) && tree.type != Type.ErrorType) + error(tree.pos, clazz + " may invoke only pure superclass constructors"); + } + + /** Check that tree represents a trait constructor. */ void checkTrait(Tree tree, Symbol clazz) { - if (!TreeInfo.isPureConstr(tree) && - tree.type != Type.ErrorType /*&& - !tree.type.symbol().isTrait()*/) - error(tree.pos, " " + clazz + " may inherit only from stable trait constructors"); + if (!tree.type.symbol().isTrait() && tree.type != Type.ErrorType) + error(tree.pos, " " + clazz + " may inherit only traits as mixins"); } /** Check that tree is a stable expression .p */ Tree checkStable(Tree tree) { - if (TreeInfo.isPureExpr(tree) || tree.type == Type.ErrorType) return tree; - //new TextTreePrinter().print(tree).end();//DEBUG - //System.out.println(" " + tree.symbol() + ":" + tree.type);//DEBUG - - //Symbol sym = tree.symbol(); - //if (sym != null) { - // System.out.println(sym.kind == VAL); - // System.out.println(sym.type().unalias()); - // System.out.println(sym.type().isObjectType()); - // System.out.println(sym.owner().isPrimaryConstructor()); - //} - - return error(tree.pos, "stable identifier required"); + if (TreeInfo.isPureExpr(tree) || tree.type == Type.ErrorType) + return tree; + else + return error(tree.pos, "stable identifier required, but " + + tree + " found."); } /** Check that class can be instantiated. @@ -606,9 +609,9 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { 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"); + overrideError(pos, member, other, "has weaker access privileges; it should not be private"); + } else if ((member.flags & PROTECTED) != 0 && (other.flags & PROTECTED) == 0) { + overrideError(pos, member, other, "has weaker access privileges; it should not be protected"); } else if ((other.flags & FINAL) != 0) { overrideError(pos, member, other, "cannot override final member"); } else if ((other.flags & DEFERRED) == 0 && ((member.flags & OVERRIDE) == 0)) { @@ -622,16 +625,22 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { overrideError(pos, member, other, "cannot override a class"); break; case ALIAS: - if (!self.memberInfo(member).isSameAs(self.memberInfo(other))) - overrideTypeError(pos, member, other, self); + if (!self.memberType(member).isSameAs(self.memberType(other))) + overrideTypeError(pos, member, other, self, false); break; default: if (other.isConstructor()) - overrideError(pos, member, other, "cannot override a class constructor"); + overrideError(pos, member, other, + "cannot override a class constructor"); Type selftype = normalizedInfo(self, member); Type othertype = normalizedInfo(self, other); if (!selftype.isSubType(othertype)) - overrideTypeError(pos, member, other, self); + overrideTypeError(pos, member, other, self, false); + if (member.kind == TYPE && + !self.memberLoBound(other).isSubType( + self.memberLoBound(member))) + overrideTypeError(pos, member, other, self, true); + } } } @@ -640,17 +649,22 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { if (other.type() != Type.ErrorType && member.type() != Type.ErrorType) error(pos, "error overriding " + other + other.locationString() + - "; " + member + member.locationString() + " " + msg); + ";\n " + member + member.locationString() + " " + msg); } - void overrideTypeError(int pos, Symbol member, Symbol other, Type site) { + void overrideTypeError(int pos, Symbol member, Symbol other, Type site, + boolean lobound) { if (other.type() != Type.ErrorType && member.type() != Type.ErrorType) { + Type memberInfo = lobound ? site.memberLoBound(member) + : normalizedInfo(site, member); + Type otherInfo = lobound ? site.memberLoBound(other) + : normalizedInfo(site, other); error(pos, member + member.locationString() + - infoString(member, normalizedInfo(site, member)) + + infoString(member, memberInfo, lobound) + "\n cannot override " + other + other.locationString() + - infoString(other, normalizedInfo(site, other))); - explainTypes(normalizedInfo(site, member), normalizedInfo(site, other)); + infoString(other, otherInfo, lobound)); + explainTypes(memberInfo, otherInfo); } } @@ -660,10 +674,10 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { return tp; } - String infoString(Symbol sym, Type symtype) { + String infoString(Symbol sym, Type symtype, boolean lobound) { switch (sym.kind) { case ALIAS: return ", which equals " + symtype; - case TYPE: return " bounded by " + symtype; + case TYPE: return " bounded" + (lobound ? " from below" : "") + " by " + symtype; case VAL: return " of type " + symtype; default: return ""; } @@ -756,8 +770,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { void validateVariance(Symbol base, Type all, Type[] tps, int variance, Symbol[] tparams) { for (int i = 0; i < tps.length; i++) -// if (tps[i] != tparams[i].type()) - validateVariance(base, all, tps[i], variance * tparams[i].variance()); + validateVariance(base, all, tps[i], variance * tparams[i].variance()); } // Entering Symbols ---------------------------------------------------------- @@ -795,7 +808,6 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { * 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): @@ -924,6 +936,8 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { } else if (sym.kind == VAL && other.kind == VAL) { // it's an overloaded definition if (((sym.flags ^ other.flags) & SOURCEFLAGS) != 0) { + // todo: refine, DEFERRED, MUTABLE and OVERRIDE should be + // treated specially; maybe only PRIVATE and PROTECTED? error(sym.pos, "illegal overloaded definition of " + sym + ": modifier lists differ in " + @@ -972,6 +986,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { Type owntype; switch (tree) { case ClassDef(int mods, Name name, Tree.TypeDef[] tparams, Tree.ValDef[][] vparams, Tree tpe, Tree.Template templ): + // todo: check why this is necessary if ((mods & LOCKED) != 0 && !sym.isAnonymousClass()) { sym.setInfo(Type.ErrorType); throw new CyclicReference(sym, Type.NoType); @@ -1015,7 +1030,8 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { pushContext(tree, sym, context.scope); if (rhs == Tree.Empty) { if ((sym.owner().flags & ACCESSOR) != 0) { - // this is the paremeter of a variable setter method. + // this is the parameter of a variable setter method. + assert (sym.flags & PARAM) != 0; ((ValDef) tree).tpe = tpe = gen.mkType(tree.pos, sym.owner().accessed().type()); } else { @@ -1027,6 +1043,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { } else { if ((mods & CASEACCESSOR) != 0) { //rhs was already attributed + assert rhs.type != null; } else { ((ValDef) tree).rhs = rhs = transform(rhs, EXPRmode); } @@ -1052,15 +1069,15 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { restpe = checkNoEscape( tpe.pos, transform(tpe, TYPEmode).type); } - checkNonCyclic(tree.pos, restpe); popContext(); + checkNonCyclic(tree.pos, restpe); owntype = makeMethodType(tparamSyms, vparamSyms, restpe); //System.out.println("methtype " + name + ":" + owntype);//DEBUG break; case TypeDef(int mods, Name name, Tree rhs, Tree lobound): - //todo: always have context.owner as owner. if (sym.kind == TYPE) { + //can't have `sym' as onwer since checkNonCyclic would fail. pushContext(rhs, context.owner, context.scope); context.delayArgs = true; owntype = transform(rhs, TYPEmode).type; @@ -1068,7 +1085,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { owntype.symbol().initialize();//to detect cycles popContext(); } else { // sym.kind == ALIAS - pushContext(tree, sym, new Scope(context.scope)); + pushContext(tree, sym, context.scope); owntype = transform(rhs, TYPEmode | FUNmode).type; popContext(); } @@ -1130,7 +1147,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { case ValDef(int mods, _, _, _): if ((mods & REPEATED) != 0 && params.length > 1) error(params[i].pos, - "`*' parameter must be the only parameter a `('...`)' section"); + "`*' parameter must be the only parameter of a `('...`)' section"); } } return Tree.symbolOf(params); @@ -1258,6 +1275,8 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { if (!sym.owner().isPackage()) { Tree qual = makeStableId(tree.pos, pre); tree = make.Select(tree.pos, qual, name); + if (context.enclClass != nextcontext.enclClass) + sym.flags |= SELECTOR; //System.out.println(name + " :::> " + tree + " " + qual.symbol());//DEBUG } } else { @@ -1288,6 +1307,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { pre = qual.type; //new TextTreePrinter().print(name + " => ").print(lastimports.tree).print("." + name).println().end();//DEBUG tree = make.Select(tree.pos, qual, name); + checkAccessible(tree.pos, sym, qual); } symtype = pre.memberType(sym); if ((pt != null && pt.isStable() || (mode & QUALmode) != 0) && sym.isStable()) { @@ -1313,10 +1333,11 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { //System.out.println(qual.type + " has members " + qual.type.members());//DEBUG return error(tree.pos, decode(name) + " is not a member of " + qual.type.widen()); - } else if (!isAccessible(sym, qual)) { - return error(tree.pos, sym + " cannot be accessed in " + qual.type); } else { - sym.flags |= (ACCESSED | SELECTOR); + checkAccessible(tree.pos, sym, qual); + sym.flags |= ACCESSED; + if (!TreeInfo.isSelf(qual, context.enclClass.owner)) + sym.flags |= SELECTOR; Type symtype = qual.type.memberType(sym); //System.out.println(sym.name + ":" + symtype);//DEBUG if (uninst.length != 0) { @@ -1371,9 +1392,8 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { 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 guard1 = (guard == Tree.Empty) ? Tree.Empty + : transform(guard, EXPRmode, definitions.BOOLEAN_TYPE); Tree body1 = transform(body, EXPRmode, pt); popContext(); return (Tree.CaseDef) copy.CaseDef(tree, pat1, guard1, body1) @@ -1391,15 +1411,16 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { error(stat.pos, "only declarations allowed here"); } Tree stat1; + int mode = TreeInfo.isDefinition(stat) ? NOmode : EXPRmode; if (exprOwner.kind != NONE && !TreeInfo.isOwnerDefinition(stat)) { pushContext(stat, exprOwner, context.scope); - if (TreeInfo.isDefinition(stat)) stat1 = transform(stat); - else stat1 = transform(stat, EXPRmode); + stat1 = transform(stat, mode); popContext(); } else { - if (TreeInfo.isDefinition(stat)) stat1 = transform(stat); - else stat1 = transform(stat, EXPRmode); + stat1 = transform(stat, mode); } + // todo: if we comment next 4 lines out, test/pos/scoping2 fails. + // find out why if (stat1 != stat && stats1 == stats) { stats1 = new Tree[stats.length]; System.arraycopy(stats, 0, stats1, 0, i); @@ -1444,8 +1465,10 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { checkAllOverrides(owner); popContext(); if (owner.isTrait()) { - for (int i = 0; i < templ.parents.length; i++) - checkTrait(parents1[i], owner); + for (int i = 0; i < templ.parents.length; i++) { + checkPureConstr(parents1[i], owner); + if (i >= 1) checkTrait(parents1[i], owner); + } for (int i = 0; i < templ.body.length; i++) checkPureDef(body1[i], owner); } @@ -1454,138 +1477,6 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { 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; - } - - // if function is overloaded with one alternative whose arity matches - // argument length, preselect this alternative. - switch (fn1.type) { - case OverloadedType(Symbol[] alts, Type[] alttypes): - int matching1 = -1; - int matching2 = -1; - for (int i = 0; i < alttypes.length; i++) { - Type alttp = alttypes[i]; - switch (alttp) { - case PolyType(_, Type restp): alttp = restp; - } - switch (alttp) { - case MethodType(Symbol[] params, _): - if (params.length == args.length || - params.length == 1 && (params[0].flags & REPEATED) != 0) { - matching2 = matching1; - matching1 = i; - } - } - } - if (matching1 >= 0 && matching2 < 0) - fn1.setSymbol(alts[matching1]).setType(alttypes[matching1]); - } - - // handle the case of application of match to a visitor specially - if (args.length == 1 && args[0] instanceof Visitor) { - Type pattp = matchQualType(fn1); - switch (fn1.type) { - case PolyType(Symbol[] tparams, _): - if (pattp.containsSome(tparams)) { - if (global.debug) System.out.println(fn1.type + "+" + pattp);//debug - pattp = Type.AnyType; // so isFullyDefined fails below. - } - } - if (pattp == Type.ErrorType) { - return tree.setType(Type.ErrorType); - } else if (pattp != Type.NoType) { - if (infer.isFullyDefined(pattp)) { - 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); - } else { - return error(tree.pos, "expected pattern type of cases could not be determined"); - } - } - } - - // 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 copy.Apply(tree, fn1, args).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.pos, 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, pt); - } catch (Type.Error ex) { - error(tree.pos, ex.msg); - } - switch (fn1.type) { - case MethodType(Symbol[] params, Type restp1): - Type[] formals = infer.formalTypes(params, args.length); - for (int i = 0; i < args.length; i++) { - args[i] = adapt(args[i], argMode, formals[i]); - } - 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.pos, - 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. @@ -1827,7 +1718,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { /** Transform expression or type with a given mode. */ public Tree transform(Tree tree, int mode) { - if ((mode & TYPEmode) == 0) + if ((mode & (EXPRmode | PATTERNmode | CONSTRmode)) != 0) return transform(tree, mode, Type.AnyType); int savedMode = this.mode; @@ -1835,13 +1726,14 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { Tree tree1 = transform(tree); this.mode = savedMode; - Symbol sym = tree1.symbol(); - if ((mode & FUNmode) == 0 && sym != null && sym.typeParams().length != 0) - return error(tree.pos, sym + " takes type parameters."); + if ((mode & TYPEmode) != 0) { + Symbol sym = tree1.symbol(); + if ((mode & FUNmode) == 0 && sym != null && sym.typeParams().length != 0) + return error(tree.pos, sym + " takes type parameters."); // else if (tree1.isType()) // return gen.mkType(tree1.pos, tree1.type); - else - return tree1; + } + return tree1; } Tree[] transform(Tree[] trees, int mode) { @@ -1920,7 +1812,9 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { popContext(); } } - validateVariance(sym, sym.type(), CoVariance); + validateVariance( + sym, sym.type(), + ((sym.flags & MUTABLE) != 0) ? NoVariance : CoVariance); return copy.ValDef(tree, sym, tpe1, rhs1) .setType(definitions.UNIT_TYPE); @@ -2155,7 +2049,131 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { ArrayApply.toString(argtypes, "[", ",", "]")); case Apply(Tree fn, Tree[] args): - return transformApply(tree, fn, args); + Tree fn1; + int argMode; + //todo: Should we pass in both cases a methodtype with + // AnyType's for args as a prototype? + 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; + } + + // if function is overloaded with one alternative whose arity matches + // argument length, preselect this alternative. + switch (fn1.type) { + case OverloadedType(Symbol[] alts, Type[] alttypes): + int matching1 = -1; + int matching2 = -1; + for (int i = 0; i < alttypes.length; i++) { + Type alttp = alttypes[i]; + switch (alttp) { + case PolyType(_, Type restp): alttp = restp; + } + switch (alttp) { + case MethodType(Symbol[] params, _): + if (params.length == args.length || + params.length == 1 && (params[0].flags & REPEATED) != 0) { + matching2 = matching1; + matching1 = i; + } + } + } + if (matching1 >= 0 && matching2 < 0) + fn1.setSymbol(alts[matching1]).setType(alttypes[matching1]); + } + + // 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) { + if (infer.isFullyDefined(pattp) && + !(fn1.type instanceof Type.PolyType && + pattp.containsSome(fn1.type.typeParams()))) { + 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); + } else { + return error(tree.pos, "expected pattern type of cases could not be determined"); + } + } + } + + // 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 copy.Apply(tree, fn1, args).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.pos, 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, pt); + } catch (Type.Error ex) { + error(tree.pos, ex.msg); + } + switch (fn1.type) { + case MethodType(Symbol[] params, Type restp1): + Type[] formals = infer.formalTypes(params, args.length); + for (int i = 0; i < args.length; i++) { + args[i] = adapt(args[i], argMode, formals[i]); + } + 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.pos, + infer.applyErrorMsg( + "", fn1, " cannot be applied to ", argtypes, pt)); case Super(Tree tpe): Symbol enclClazz = context.enclClass.owner; @@ -2190,7 +2208,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { } } else { Tree qual1 = transform(qual, TYPEmode | FUNmode); - clazz = qual1.type.symbol(); + clazz = qual1.symbol(); if (clazz.kind == CLASS) { Context clazzContext = context.outerContext(clazz); if (clazzContext != Context.NONE) { diff --git a/sources/scalac/typechecker/DeSugarize.java b/sources/scalac/typechecker/DeSugarize.java index f6f1943e5e..e5f2b2095d 100644 --- a/sources/scalac/typechecker/DeSugarize.java +++ b/sources/scalac/typechecker/DeSugarize.java @@ -525,7 +525,7 @@ public class DeSugarize implements Kinds, Modifiers { Tree.TypeDef_EMPTY_ARRAY, new ValDef[][]{{ (ValDef) make.ValDef( - tree.pos, SYNTHETIC, parameterName(0), tpe, Tree.Empty)}}, + tree.pos, SYNTHETIC | PARAM, parameterName(0), tpe, Tree.Empty)}}, gen.mkType(tree.pos, global.definitions.UNIT_TYPE), ((mods1 & DEFERRED) != 0) ? Tree.Empty : make.Assign( diff --git a/sources/scalac/typechecker/Infer.java b/sources/scalac/typechecker/Infer.java index b3cd5436df..a212e26e77 100644 --- a/sources/scalac/typechecker/Infer.java +++ b/sources/scalac/typechecker/Infer.java @@ -614,9 +614,11 @@ public class Infer implements Modifiers, Kinds { if (!isCompatible(argtypes[i].widen().subst(tparams, tvars), formals[i].subst(tparams, tvars))) { if (needToSucceed) { - if (Type.debugSwitch) { + if (global.explaintypes) { + Type.explainSwitch = true; argtypes[i].widen().subst(tparams, tvars).isSubType( formals[i].subst(tparams, tvars)); + Type.explainSwitch = false; } throw new NoInstance( typeErrorMsg( diff --git a/sources/scalac/util/Name.java b/sources/scalac/util/Name.java index 2522cb59f8..0978c7589d 100644 --- a/sources/scalac/util/Name.java +++ b/sources/scalac/util/Name.java @@ -338,9 +338,11 @@ public final class Name { /** is this name a variable identifier? */ public boolean isVariable() { - return ((names[index] >= 'a') && (names[index] <= 'z')) || - (names[index] == '_') && - this != Names.null_; + return ((names[index] >= 'a' && names[index] <= 'z') || + names[index] == '_') && + this != Names.null_ && + this != Names.true_ && + this != Names.false_; } public static final Name ERROR = Name.fromString(""); diff --git a/sources/scalac/util/Names.java b/sources/scalac/util/Names.java index f8a0e709b6..b7e2b0e0c2 100644 --- a/sources/scalac/util/Names.java +++ b/sources/scalac/util/Names.java @@ -60,6 +60,7 @@ public class Names { public static final Name as = Name.fromString("as"); public static final Name box = Name.fromString("box"); public static final Name elem = Name.fromString("elem"); + public static final Name false_ = Name.fromString("false"); public static final Name filter = Name.fromString("filter"); public static final Name flatmap = Name.fromString("flatMap"); public static final Name foreach = Name.fromString("foreach"); @@ -114,6 +115,7 @@ public class Names { public static final Name that = Name.fromString("that"); public static final Name this_ = Name.fromString("this"); public static final Name throw_ = Name.fromString("throw"); + public static final Name true_ = Name.fromString("true"); public static final Name update = Name.fromString("update"); public static final Name -- cgit v1.2.3