From f115eda9c9bc97313591ca699e07fa2a117cc997 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 2 Apr 2003 07:32:39 +0000 Subject: *** empty log message *** --- sources/scalac/ast/TreeGen.java | 10 +- sources/scalac/ast/printer/TextTreePrinter.java | 5 +- sources/scalac/symtab/Symbol.java | 5 + sources/scalac/transformer/PatternMatcher.java | 13 +- .../transformer/matching/PatternMatcher.java | 13 +- sources/scalac/typechecker/Analyzer.java | 38 ++-- sources/scalac/typechecker/DeSugarize.java | 6 +- sources/scalac/typechecker/Infer.java | 4 +- sources/scalac/typechecker/RefCheck.java | 205 +++++++++++++++++++-- sources/scalac/util/Names.java | 4 +- 10 files changed, 245 insertions(+), 58 deletions(-) (limited to 'sources') diff --git a/sources/scalac/ast/TreeGen.java b/sources/scalac/ast/TreeGen.java index 18275af3a7..864609e7f8 100644 --- a/sources/scalac/ast/TreeGen.java +++ b/sources/scalac/ast/TreeGen.java @@ -56,7 +56,7 @@ public class TreeGen implements Kinds, Modifiers { /*************************************************************************/ /** METHODS **/ - private Type deref(Type tp) { + public Type deref(Type tp) { switch (tp) { case PolyType(Symbol[] tparams, Type restp): if (tparams.length == 0) return restp; @@ -160,7 +160,7 @@ public class TreeGen implements Kinds, Modifiers { /** Build a boolean constant tree. */ - public Tree mkBoolean(int pos, boolean bool) { + public Tree mkBooleanLit(int pos, boolean bool) { return make.Literal(pos, bool ? Boolean.TRUE : Boolean.FALSE). setType(definitions.BOOLEAN_TYPE); } @@ -171,6 +171,12 @@ public class TreeGen implements Kinds, Modifiers { return make.Literal(pos, str).setType(definitions.JAVA_STRING_TYPE); } + /** Build an integer literal + */ + public Tree mkIntLit(int pos, int value) { + return make.Literal(pos, new Integer(value)).setType(definitions.INT_TYPE); + } + /** Build a tree to be used as a base class constructor for a template. */ public Tree mkParentConstr(int pos, Type parentType) { diff --git a/sources/scalac/ast/printer/TextTreePrinter.java b/sources/scalac/ast/printer/TextTreePrinter.java index 0d4ff6022f..36401bcab1 100644 --- a/sources/scalac/ast/printer/TextTreePrinter.java +++ b/sources/scalac/ast/printer/TextTreePrinter.java @@ -427,7 +427,10 @@ public class TextTreePrinter implements TreePrinter { break; case Apply(Tree fun, Tree[] vargs): - print(fun); + if (fun instanceof Tree.TypeTerm) + print(fun.type.resultType().symbol().fullName().toString()); + else + print(fun); printArray(vargs, TXT_LEFT_PAREN, TXT_RIGHT_PAREN, TXT_COMMA_SP); printType(tree); break; diff --git a/sources/scalac/symtab/Symbol.java b/sources/scalac/symtab/Symbol.java index 7ecbfe543a..71d8a7c142 100644 --- a/sources/scalac/symtab/Symbol.java +++ b/sources/scalac/symtab/Symbol.java @@ -187,6 +187,11 @@ public abstract class Symbol implements Modifiers, Kinds { return isInitializedMethod(); } + public final boolean isAbstractClass() { + return (flags & ABSTRACTCLASS) != 0 && + this != Global.instance.definitions.ARRAY_CLASS; + } + /* Does this symbol denote an anonymous class? */ public final boolean isAnonymousClass() { return kind == CLASS && diff --git a/sources/scalac/transformer/PatternMatcher.java b/sources/scalac/transformer/PatternMatcher.java index e1dc0c0503..1ab354301e 100644 --- a/sources/scalac/transformer/PatternMatcher.java +++ b/sources/scalac/transformer/PatternMatcher.java @@ -661,7 +661,7 @@ public class PatternMatcher { } protected Tree toTree(PatternNode node) { - Tree res = mkBoolean(node.pos, false); + Tree res = gen.mkBooleanLit(node.pos, false); while (node != null) switch (node) { case Header(Tree selector, Header next): @@ -681,7 +681,7 @@ public class PatternMatcher { make.Ident(body[i].pos, resultVar.name) .setType(typeOf(resultVar)).setSymbol(resultVar), body[i]).setType(defs.UNIT_TYPE), - mkBoolean(body[i].pos, true) + gen.mkBooleanLit(body[i].pos, true) }, defs.BOOLEAN_TYPE); if (guard[i] != Tree.Empty) ts[bound[i].length] = mkAnd(guard[i], ts[bound[i].length]); @@ -696,7 +696,7 @@ public class PatternMatcher { protected Tree toTree(PatternNode node, Tree selector) { if (node == null) - return mkBoolean(selector.pos, false); + return gen.mkBooleanLit(selector.pos, false); switch (node) { case DefaultPat(): return toTree(node.and); @@ -779,15 +779,10 @@ public class PatternMatcher { return make.Block(pos, ts).setType(tpe); } - protected Tree mkBoolean(int pos, boolean bool) { - Boolean val = bool ? Boolean.TRUE : Boolean.FALSE; - return make.Literal(pos, val).setType(defs.BOOLEAN_TYPE); - } - protected Tree mkNegate(Tree tree) { switch (tree) { case Literal(Object value): - return mkBoolean(tree.pos, !((Boolean)value).booleanValue()); + return gen.mkBooleanLit(tree.pos, !((Boolean)value).booleanValue()); } return make.Apply( tree.pos, diff --git a/sources/scalac/transformer/matching/PatternMatcher.java b/sources/scalac/transformer/matching/PatternMatcher.java index e1dc0c0503..1ab354301e 100644 --- a/sources/scalac/transformer/matching/PatternMatcher.java +++ b/sources/scalac/transformer/matching/PatternMatcher.java @@ -661,7 +661,7 @@ public class PatternMatcher { } protected Tree toTree(PatternNode node) { - Tree res = mkBoolean(node.pos, false); + Tree res = gen.mkBooleanLit(node.pos, false); while (node != null) switch (node) { case Header(Tree selector, Header next): @@ -681,7 +681,7 @@ public class PatternMatcher { make.Ident(body[i].pos, resultVar.name) .setType(typeOf(resultVar)).setSymbol(resultVar), body[i]).setType(defs.UNIT_TYPE), - mkBoolean(body[i].pos, true) + gen.mkBooleanLit(body[i].pos, true) }, defs.BOOLEAN_TYPE); if (guard[i] != Tree.Empty) ts[bound[i].length] = mkAnd(guard[i], ts[bound[i].length]); @@ -696,7 +696,7 @@ public class PatternMatcher { protected Tree toTree(PatternNode node, Tree selector) { if (node == null) - return mkBoolean(selector.pos, false); + return gen.mkBooleanLit(selector.pos, false); switch (node) { case DefaultPat(): return toTree(node.and); @@ -779,15 +779,10 @@ public class PatternMatcher { return make.Block(pos, ts).setType(tpe); } - protected Tree mkBoolean(int pos, boolean bool) { - Boolean val = bool ? Boolean.TRUE : Boolean.FALSE; - return make.Literal(pos, val).setType(defs.BOOLEAN_TYPE); - } - protected Tree mkNegate(Tree tree) { switch (tree) { case Literal(Object value): - return mkBoolean(tree.pos, !((Boolean)value).booleanValue()); + return gen.mkBooleanLit(tree.pos, !((Boolean)value).booleanValue()); } return make.Apply( tree.pos, diff --git a/sources/scalac/typechecker/Analyzer.java b/sources/scalac/typechecker/Analyzer.java index ee545ac7d3..6e7930c32b 100644 --- a/sources/scalac/typechecker/Analyzer.java +++ b/sources/scalac/typechecker/Analyzer.java @@ -537,6 +537,15 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { 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"); } @@ -545,7 +554,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { void checkInstantiatable(int pos, Type tp) { Symbol clazz = tp.symbol(); if (clazz.kind == CLASS) { - if ((clazz.flags & ABSTRACTCLASS) != 0) + if (clazz.isAbstractClass()) error(pos, clazz + " is abstract, so it cannot be instantiated"); else if (!tp.isSubType(tp.instanceType())) error(pos, tp + " does not conform to its self-type " + @@ -1566,6 +1575,8 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { this.pt = pt; Tree tree1 = adapt(transform(tree), mode, pt); + //new TextTreePrinter().print(tree1).print(": " + tree1.type).println().end();//DEBUG + this.mode = savedMode; this.pt = savedPt; return tree1; @@ -1697,25 +1708,12 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { return adapt(tree, mode, pt); } } - } else { - Symbol fsym = TreeInfo.methSymbol(tree); - if (fsym != null && fsym.isMethod() && (fsym.flags & CASE) != 0) { - // convert case methods to new's - Symbol constr = fsym.owner().info() - .lookup(fsym.name.toTypeName()).constructor(); - Template templ = make.Template( - tree.pos, - new Tree[]{desugarize.toConstructor(tree, constr)}, - Tree.EMPTY_ARRAY); - return transform(make.New(tree.pos, templ), mode, pt); - } else if ((mode & QUALmode) == 0) { - // 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"); - } + } else if ((mode & QUALmode) == 0) { + // 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()) { + error(tree.pos, tree.symbol() + " is not a value"); } } } diff --git a/sources/scalac/typechecker/DeSugarize.java b/sources/scalac/typechecker/DeSugarize.java index 91faf4adb6..28acac2d35 100644 --- a/sources/scalac/typechecker/DeSugarize.java +++ b/sources/scalac/typechecker/DeSugarize.java @@ -299,7 +299,7 @@ public class DeSugarize implements Kinds, Modifiers { make.CaseDef(lastCase.pos, lastCase.pat.duplicate(), Tree.Empty, - gen.mkBoolean(lastCase.body.pos, true))}); + gen.mkBooleanLit(lastCase.body.pos, true))}); } CaseDef[] cases1 = new CaseDef[cases.length + 1]; for (int i = 0; i < cases.length; i++) { @@ -309,14 +309,14 @@ public class DeSugarize implements Kinds, Modifiers { cases[i].pos, pat.duplicate(), guard.duplicate(), - gen.mkBoolean(tree.pos, true)); + gen.mkBooleanLit(tree.pos, true)); } } cases1[cases.length] = (CaseDef) make.CaseDef( tree.pos, make.Ident(tree.pos, Names.WILDCARD), Tree.Empty, - gen.mkBoolean(tree.pos, false)); + gen.mkBooleanLit(tree.pos, false)); return make.Visitor(tree.pos, cases1); default: throw new ApplicationError("visitor expected", tree); diff --git a/sources/scalac/typechecker/Infer.java b/sources/scalac/typechecker/Infer.java index 10cd793f3e..fcbc88cd64 100644 --- a/sources/scalac/typechecker/Infer.java +++ b/sources/scalac/typechecker/Infer.java @@ -693,10 +693,12 @@ public class Infer implements Modifiers, Kinds { for (int i = 0; i < tvars.length; i++) { try { targs[i] = instantiateUpper(tvars[i], true); + if (targs[i] == Type.AnyType) + targs[i] = definitions.ANY_TYPE; } catch (NoInstance ex) { throw new Type.Error( "constructor of type " + ctpe1 + - " can be instantiated in mode than one way to expected type " + + " can be instantiated in more than one way to expected type " + pt + "\n --- because ---\n" + ex.getMessage()); } diff --git a/sources/scalac/typechecker/RefCheck.java b/sources/scalac/typechecker/RefCheck.java index d6a3515eea..d18daac17f 100644 --- a/sources/scalac/typechecker/RefCheck.java +++ b/sources/scalac/typechecker/RefCheck.java @@ -9,6 +9,7 @@ import java.util.HashMap; import scalac.*; import scalac.util.*; import scalac.ast.*; +import scalac.ast.printer.*; import scalac.symtab.*; import Tree.*; @@ -183,8 +184,8 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { } private Tree[] caseFields(ClassSymbol clazz) { - Symbol[] tparams = clazz.typeParams(); - Tree[] fields = new Tree[clazz.constructor().type().firstParams().length]; + Symbol[] vparams = clazz.constructor().type().firstParams(); + Tree[] fields = new Tree[vparams.length]; for (int i = 0; i < fields.length; i++) { fields[i] = gen.mkRef( clazz.pos, clazz.thisType(), clazz.caseFieldAccessor(i)); @@ -193,6 +194,10 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { } private Tree toStringMethod(ClassSymbol clazz) { + Symbol toStringSym = new TermSymbol( + clazz.pos, Names.toString, clazz, OVERRIDE) + .setInfo(definitions.TOSTRING.type()); + clazz.info().members().enter(toStringSym); Tree[] fields = caseFields(clazz); Tree body; if (fields.length == 0) { @@ -210,20 +215,137 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { new Tree[]{gen.mkStringLit(clazz.pos, (i == fields.length - 1) ? ")" : ",")}); } } - Symbol toStringSym = new TermSymbol( - clazz.pos, Names.toString, clazz, OVERRIDE) - .setInfo(definitions.TOSTRING.type()); - clazz.info().members().enter(toStringSym); return gen.DefDef(clazz.pos, toStringSym, body); } private Tree equalsMethod(ClassSymbol clazz) { - return Tree.Empty; + Symbol equalsSym = new TermSymbol(clazz.pos, Names.EQEQ, clazz, OVERRIDE); + Symbol equalsParam = + new TermSymbol(clazz.pos, Names.that, equalsSym, PARAM) + .setInfo(definitions.ANY_TYPE); + equalsSym.setInfo( + Type.MethodType(new Symbol[]{equalsParam}, definitions.BOOLEAN_TYPE)); + clazz.info().members().enter(equalsSym); + Tree[] fields = caseFields(clazz); + Tree[] patargs = patternVars(clazz, equalsSym); + Type constrtype = clazz.constructor().type(); + switch (constrtype) { + case PolyType(Symbol[] tparams, Type restp): + Type[] targs = new Type[tparams.length]; + for (int i = 0; i < targs.length; i++) + targs[i] = definitions.ANY_TYPE; + constrtype = restp.subst(tparams, targs); + } + Tree pattern = make.Apply( + clazz.pos, gen.mkType(clazz.pos, constrtype), patargs) + .setType(clazz.type()); + Tree rhs; + if (fields.length == 0) { + rhs = gen.mkBooleanLit(clazz.pos, true); + } else { + rhs = eqOp(fields[0], patargs[0]); + for (int i = 1; i < fields.length; i++) { + rhs = gen.Apply( + gen.Select(rhs, definitions.AMPAMP()), + new Tree[]{eqOp(fields[i], patargs[i])}); + } + } + CaseDef case1 = (Tree.CaseDef) make.CaseDef( + clazz.pos, pattern, Tree.Empty, rhs) + .setType(definitions.BOOLEAN_TYPE); + CaseDef case2 = (Tree.CaseDef) make.CaseDef(clazz.pos, + patternVar(clazz.pos, Names.WILDCARD, equalsSym), + Tree.Empty, + gen.mkBooleanLit(clazz.pos, false)) + .setType(definitions.BOOLEAN_TYPE); + Tree body = make.Apply(clazz.pos, + gen.Select( + gen.mkRef(clazz.pos, Type.localThisType, equalsParam), + definitions.MATCH), + new Tree[]{make.Visitor(clazz.pos, new CaseDef[]{case1, case2}) + .setType(definitions.BOOLEAN_TYPE)}) + .setType(definitions.BOOLEAN_TYPE); + return gen.DefDef(clazz.pos, equalsSym, body); } + //where + private Tree patternVar(int pos, Name name, Symbol owner) { + return make.Ident(pos, name) + .setSymbol(new TermSymbol(pos, name, owner, 0) + .setType(definitions.ANY_TYPE)) + .setType(definitions.ANY_TYPE); + } + + private Tree[] patternVars(ClassSymbol clazz, Symbol owner) { + Symbol[] vparams = clazz.constructor().type().firstParams(); + Tree[] pats = new Tree[vparams.length]; + for (int i = 0; i < pats.length; i++) { + pats[i] = patternVar(clazz.pos, vparams[i].name, owner); + } + return pats; + } + + private Tree eqOp(Tree l, Tree r) { + return gen.Apply(gen.Select(l, definitions.EQEQ), new Tree[]{r}); + } private Tree hashCodeMethod(ClassSymbol clazz) { - return Tree.Empty; + Symbol hashCodeSym = new TermSymbol( + clazz.pos, Names.hashCode, clazz, OVERRIDE) + .setInfo(definitions.HASHCODE.type()); + clazz.info().members().enter(hashCodeSym); + Tree[] fields = caseFields(clazz); + Symbol getClassSym = getMember(clazz.type(), Names.getClass); + Symbol addSym = intMethod(Names.ADD); + Symbol mulSym = intMethod(Names.MUL); + Tree body = + gen.Apply( + gen.Select( + gen.Apply( + gen.mkRef(clazz.pos, clazz.thisType(), getClassSym), + Tree.EMPTY_ARRAY), + getMember(getClassSym.type().resultType(), Names.hashCode)), + Tree.EMPTY_ARRAY); + for (int i = 0; i < fields.length; i++) { + Tree operand = gen.Apply( + gen.Select( + fields[i], + getMember(fields[i].type, Names.hashCode)), + Tree.EMPTY_ARRAY); + body = + gen.Apply( + gen.Select( + gen.Apply( + gen.Select(body, mulSym), + new Tree[]{gen.mkIntLit(clazz.pos, 41)}), + addSym), + new Tree[]{operand}); + } + return gen.DefDef(clazz.pos, hashCodeSym, body); } + // where + private Symbol getMember(Type site, Name name) { + Symbol sym = site.lookupNonPrivate(name); + assert sym.kind == VAL; + return sym; + } + + private Symbol intMethod(Name name) { + Symbol sym = getMember(definitions.INT_TYPE, name); + switch (sym.type()) { + case OverloadedType(Symbol[] alts, Type[] alttypes): + for (int i = 0; i < alts.length; i++) { + if (hasIntParam(alttypes[i])) return alts[i]; + } + } + assert hasIntParam(sym.type()) : "no int method among " + sym.type(); + return sym; + } + + private boolean hasIntParam(Type tp) { + Symbol[] params = tp.firstParams(); + return params.length == 1 && + params[0].type().isSameAs(definitions.INT_TYPE); + } private Template addCaseMethods(Template templ, Symbol sym) { if (sym.kind == CLASS && (sym.flags & CASE) != 0) { @@ -237,12 +359,10 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { TreeList ts = new TreeList(); if (!hasImplementation(clazz, Names.toString)) ts.append(toStringMethod(clazz)); -/* if (!hasImplementation(clazz, Names.EQEQ)) ts.append(equalsMethod(clazz)); if (!hasImplementation(clazz, Names.hashCode)) ts.append(hashCodeMethod(clazz)); -*/ if (ts.length() > 0) { Tree[] stats1 = new Tree[stats.length + ts.length()]; System.arraycopy(stats, 0, stats1, 0, stats.length); @@ -253,6 +373,67 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { } } + public Tree convertCaseFactoryCall(Tree tree) { + Symbol fsym = TreeInfo.methSymbol(tree); + if (fsym != null && fsym.isMethod() && !fsym.isConstructor() && + (fsym.flags & CASE) != 0) { + // convert case methods to new's + Symbol constr = fsym.owner().info() + .lookup(fsym.name.toTypeName()).constructor(); + return gen.New(toConstructor(tree, constr)); + } else { + return tree; + } + } + //where + /** Tree represents an application of a constructor method of a case class + * (whose name is a term name). Convert this tree to application of + * the case classe's primary constructor `constr'. + */ + private Tree toConstructor(Tree tree, Symbol constr) { + switch (tree) { + case Apply(Tree fn, Tree[] args): + return copy.Apply(tree, toConstructor1(fn, constr), args); + default: + return gen.Apply( + tree.pos, toConstructor1(tree, constr), Tree.EMPTY_ARRAY); + } + } + + private Tree toConstructor1(Tree tree, Symbol constr) { + switch (tree) { + case TypeApply(Tree fn, Tree[] args): + return toMethodType( + copy.TypeApply(tree, toConstructor1(fn, constr), args)); + case Ident(Name name): + return toMethodType( + copy.Ident(tree, constr.name).setSymbol(constr)); + case Select(Tree qual, Name name): + return toMethodType( + copy.Select(tree, qual, constr.name).setSymbol(constr)); + default: + throw new ApplicationError(); + } + } + + private Tree toMethodType(Tree tree) { + Type tp = toMethodType(tree.type); + if (tp == tree.type) return tree; + else return tree.duplicate().setType(tp); + } + + private Type toMethodType(Type tp) { + switch (tp) { + case MethodType(_, _): + return tp; + case PolyType(Symbol[] tparams, Type restp): + Type restp1 = toMethodType(restp); + if (restp == restp) return tp; + else return Type.PolyType(tparams, restp1); + default: + return Type.MethodType(Symbol.EMPTY_ARRAY, tp); + } + } /** The main checking functions */ @@ -314,10 +495,10 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { maxindex[i] = symindex; } } - tree1 = tree; + tree1 = convertCaseFactoryCall(tree); break; default: - tree1 = super.transform(tree); + tree1 = super.transform(convertCaseFactoryCall(tree)); } if (tree1.isType() && !tree1.isMissing()) tree1 = gen.mkType(tree1.pos, tree1.type); diff --git a/sources/scalac/util/Names.java b/sources/scalac/util/Names.java index a7bc70d534..60afc67ffa 100644 --- a/sources/scalac/util/Names.java +++ b/sources/scalac/util/Names.java @@ -59,6 +59,7 @@ public class Names { public static final Name filter = Name.fromString("filter"); public static final Name flatmap = Name.fromString("flatMap"); public static final Name foreach = Name.fromString("foreach"); + public static final Name getClass = Name.fromString("getClass"); public static final Name hashCode = Name.fromString("hashCode"); public static final Name is = Name.fromString("is"); public static final Name isDefinedAt = Name.fromString("isDefinedAt"); @@ -68,6 +69,7 @@ public class Names { public static final Name java_lang_String = Name.fromString("java.lang.String"); public static final Name java_lang_Throwable = Name.fromString("java.lang.Throwable"); public static final Name lang = Name.fromString("lang"); + public static final Name length = Name.fromString("length"); public static final Name match = Name.fromString("match"); public static final Name map = Name.fromString("map"); public static final Name null_ = Name.fromString("null"); @@ -103,10 +105,10 @@ public class Names { public static final Name scala_runtime_RunTime = Name.fromString("scala.runtime.RunTime"); public static final Name equals = Name.fromString("equals"); public static final Name toString = Name.fromString("toString"); + 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 update = Name.fromString("update"); - public static final Name length = Name.fromString("length"); public static final Name ZNOT = encode("!"), -- cgit v1.2.3