diff options
author | Martin Odersky <odersky@gmail.com> | 2003-06-11 12:01:19 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2003-06-11 12:01:19 +0000 |
commit | c055dc83e3ad095ec287d19d0b0c620241c70580 (patch) | |
tree | 847db3cd56e35920233bae54ca2b8d37ebc4e65f | |
parent | 34cdd069a106b0889594f3c784e39b1ce1d8f3af (diff) | |
download | scala-c055dc83e3ad095ec287d19d0b0c620241c70580.tar.gz scala-c055dc83e3ad095ec287d19d0b0c620241c70580.tar.bz2 scala-c055dc83e3ad095ec287d19d0b0c620241c70580.zip |
*** empty log message ***
22 files changed, 1151 insertions, 988 deletions
diff --git a/sources/meta/scalac/Phase.java b/sources/meta/scalac/Phase.java index eeeb32aa58..023ec454e2 100644 --- a/sources/meta/scalac/Phase.java +++ b/sources/meta/scalac/Phase.java @@ -19,6 +19,7 @@ public class Phase { PARSER = new Phase("parser", "PARSER"), ANALYZER = new Phase("analyzer", "ANALYZER"), DESUGARIZER = new Phase("desugarizer", "ANALYZER"), + REFCHECK = new Phase("refcheck", "REFCHECK"), UNCURRY = new Phase("uncurry", "UNCURRY"), LAMBDALIFT = new Phase("lambdalift", "LAMBDALIFT"), TRANSMATCH = new Phase("transmatch", "TRANSMATCH"), diff --git a/sources/meta/scalac/ast/Tree.java b/sources/meta/scalac/ast/Tree.java index 43a50fe3d4..0774958f12 100644 --- a/sources/meta/scalac/ast/Tree.java +++ b/sources/meta/scalac/ast/Tree.java @@ -315,30 +315,30 @@ public class Tree { n_SingletonType. setDescription("Singleton type"). - setRange(Phase.PARSER, Phase.ANALYZER). + setRange(Phase.PARSER, Phase.REFCHECK). addField(t_TermTree, "ref"); n_SelectFromType. setDescription("Type selection"). - setRange(Phase.PARSER, Phase.ANALYZER). + setRange(Phase.PARSER, Phase.REFCHECK). addField(t_TypeTree, "qualifier"). addField(t_TypeName, "selector", SymName); n_FunType. setDescription("Function type"). - setRange(Phase.PARSER, Phase.ANALYZER). + setRange(Phase.PARSER, Phase.REFCHECK). addField(t_TypeTrees, "argtpes"). addField(t_TypeTree, "restpe"); n_CompoundType. setDescription("Object type (~ Template)"). - setRange(Phase.PARSER, Phase.ANALYZER). + setRange(Phase.PARSER, Phase.REFCHECK). addField(t_TypeTrees, "parents"). addField(t_Trees, "refinements"); n_AppliedType. setDescription("Applied type"). - setRange(Phase.PARSER, Phase.ANALYZER). + setRange(Phase.PARSER, Phase.REFCHECK). addField(t_TypeTree, "tpe"). addField(t_TypeTrees, "args"); diff --git a/sources/scala/tools/scalai/Environment.java b/sources/scala/tools/scalai/Environment.java index 1cb4c240fa..3214be29c1 100644 --- a/sources/scala/tools/scalai/Environment.java +++ b/sources/scala/tools/scalai/Environment.java @@ -151,7 +151,7 @@ public class Environment { private void loadOwner(String what, Symbol symbol) { assert Debug.log("search ", what, ": ", symbol); - assert symbol.owner().isType() : Debug.show(symbol); + assert symbol.owner().isType() : Debug.show(symbol) + " " + symbol.owner(); assert!symbol.owner().isJava() : Debug.show(symbol); loadTemplate(symbol.owner()); } diff --git a/sources/scalac/ast/TreeGen.java b/sources/scalac/ast/TreeGen.java index 7fef0be2b8..6a6c4903d5 100644 --- a/sources/scalac/ast/TreeGen.java +++ b/sources/scalac/ast/TreeGen.java @@ -540,6 +540,8 @@ public class TreeGen implements Kinds, Modifiers { return ClassDef(clazz.pos, clazz, constrs, body); } + + /** Generate class definition from class symbol and body. * All parents must by parameterless, or take unit parameters. */ @@ -555,44 +557,105 @@ public class TreeGen implements Kinds, Modifiers { } /** Build the expansion of (() => expr) - * This is: - * { class $anon() extends scala.Function0 { def apply() = expr } ; new $anon() } */ public Tree mkUnitFunction(Tree expr, Type tp, Symbol owner) { - int pos = expr.pos; - Type f0t = definitions.functionType(Type.EMPTY_ARRAY, tp); + return mkFunction(expr.pos, Tree.ValDef_EMPTY_ARRAY, expr, tp, owner); + } + + /** Build the expansion of ((vparams_1, ..., vparams_n) => body) + * with result type `restype', where `owner' is the previous owner + * of `body'. + * This is: + * { class $anon() extends scala.Object with + * scala.Function_N[T_1, ..., T_n, restype] { + * def apply(vparams_1, ..., vparams_n) = body1 + * } + * new $anon() + * } + * where + * vparams_i: T_i + * `body1' results from `body' by changing owner of all defined + * symbols in `body' from `owner' to the apply method. + */ + public Tree mkFunction(int pos, ValDef[] vparams, Tree body, Type restype, + Symbol owner) { + int n = vparams.length; + Symbol[] params = new Symbol[n]; + Type[] argtypes = new Type[n]; + for (int i = 0; i < n; i++) { + params[i] = vparams[i].symbol(); + argtypes[i] = params[i].type(); + } + Type ft = definitions.functionType(argtypes, restype); ClassSymbol clazz = new ClassSymbol( pos, Names.ANON_CLASS_NAME.toTypeName(), owner, 0); - clazz.setInfo(Type.compoundType(new Type[]{definitions.OBJECT_TYPE, f0t}, + clazz.setInfo(Type.compoundType(new Type[]{definitions.OBJECT_TYPE, ft}, new Scope(), clazz)); clazz.constructor().setInfo( Type.MethodType(Symbol.EMPTY_ARRAY, clazz.typeConstructor())); Symbol applyMeth = new TermSymbol(pos, Names.apply, clazz, FINAL) - .setInfo(Type.MethodType(Symbol.EMPTY_ARRAY, tp)); + .setInfo(Type.MethodType(params, restype)); clazz.info().members().enter(applyMeth); - Tree applyDef = DefDef(applyMeth, changeOwner(expr, owner, applyMeth)); + for (int i = 0; i < params.length; i++) { + params[i].setOwner(applyMeth); + } + changeOwner(body, owner, applyMeth); + Tree applyDef = DefDef(applyMeth, body); Tree classDef = ClassDef(clazz, new Tree[]{applyDef}); Tree alloc = New(pos, Type.localThisType, clazz, Tree.EMPTY_ARRAY); return Block(new Tree[]{classDef, alloc}); } + public Tree mkPartialFunction(int pos, Tree applyVisitor, Tree isDefinedAtVisitor, + Type pattype, Type restype, Symbol owner) { + Type pft = definitions.partialFunctionType(pattype, restype); + ClassSymbol clazz = new ClassSymbol( + pos, Names.ANON_CLASS_NAME.toTypeName(), owner, 0); + clazz.setInfo(Type.compoundType(new Type[]{definitions.OBJECT_TYPE, pft}, + new Scope(), clazz)); + clazz.constructor().setInfo( + Type.MethodType(Symbol.EMPTY_ARRAY, clazz.typeConstructor())); + + Tree classDef = ClassDef(clazz, new Tree[]{ + makeVisitorMethod(pos, Names.apply, applyVisitor, + pattype, restype, clazz, owner), + makeVisitorMethod(pos, Names.isDefinedAt, isDefinedAtVisitor, + pattype, definitions.BOOLEAN_TYPE, clazz, owner)}); + Tree alloc = New(pos, Type.localThisType, clazz, Tree.EMPTY_ARRAY); + return Block(new Tree[]{classDef, alloc}); + } + //where + private Tree makeVisitorMethod(int pos, Name name, Tree visitor, + Type pattype, Type restype, + Symbol clazz, Symbol prevOwner) { + Symbol meth = new TermSymbol(pos, name, clazz, FINAL); + Symbol param = new TermSymbol(pos, Name.fromString("x$"), meth, PARAM) + .setInfo(pattype); + meth.setInfo(Type.MethodType(new Symbol[]{param}, restype)); + clazz.info().members().enter(meth); + changeOwner(visitor, prevOwner, meth); + Tree body = Apply( + Select(Ident(param), definitions.MATCH), new Tree[]{visitor}); + return DefDef(meth, body); + } + /** Change owner of all defined symbols from `prevOwner' to `newOwner' */ - public Tree changeOwner(Tree tree, final Symbol prevOwner, final Symbol newOwner) { - Transformer lifter = new Transformer(global) { - public Tree transform(Tree tree) { + public void changeOwner(Tree tree, final Symbol prevOwner, final Symbol newOwner) { + Traverser lifter = new Traverser() { + public void traverse(Tree tree) { if (TreeInfo.isDefinition(tree)) { Symbol sym = tree.symbol(); if (sym != null && sym.owner() == prevOwner) { sym.setOwner(newOwner); } } - return super.transform(tree); + super.traverse(tree); } }; - return lifter.transform(tree); + lifter.traverse(tree); } } diff --git a/sources/scalac/ast/printer/TextTreePrinter.java b/sources/scalac/ast/printer/TextTreePrinter.java index 6ed0e0d9b7..39e8f1edcf 100644 --- a/sources/scalac/ast/printer/TextTreePrinter.java +++ b/sources/scalac/ast/printer/TextTreePrinter.java @@ -415,13 +415,13 @@ public class TextTreePrinter implements TreePrinter { break; case Function(Tree.ValDef[] vparams, Tree body): - print(TXT_LEFT_BRACE); + print(TXT_LEFT_PAREN); printParams(vparams); print(Text.Space); print(TXT_RIGHT_ARROW); print(Text.Space); print(body); - print(TXT_RIGHT_BRACE); + print(TXT_RIGHT_PAREN); break; case Assign(Tree lhs, Tree rhs): @@ -564,7 +564,7 @@ public class TextTreePrinter implements TreePrinter { break; case Template(Tree[] parents, Tree[] body): - Debug.abort("unexpected case", tree); + Debug.abort("unexpected case: template"); break; default: diff --git a/sources/scalac/symtab/Symbol.java b/sources/scalac/symtab/Symbol.java index 65184b2134..57e85283a4 100644 --- a/sources/scalac/symtab/Symbol.java +++ b/sources/scalac/symtab/Symbol.java @@ -771,7 +771,8 @@ public abstract class Symbol implements Modifiers, Kinds { /** String representation of location. */ public String locationString() { - if (owner.kind == CLASS && !owner.isAnonymousClass() || + if (owner.kind == CLASS && + !owner.isAnonymousClass() && !owner.isCompoundSym() || Global.instance.debug) return " in " + owner; else diff --git a/sources/scalac/symtab/SymbolTablePrinter.java b/sources/scalac/symtab/SymbolTablePrinter.java index fdfeb0d95a..5b829d4722 100644 --- a/sources/scalac/symtab/SymbolTablePrinter.java +++ b/sources/scalac/symtab/SymbolTablePrinter.java @@ -513,14 +513,15 @@ public class SymbolTablePrinter { case ThisType(Symbol sym): if (sym == Symbol.NONE) return print("<local>.this"); if (sym.isRoot()) return print("<root>.this"); - if (sym.isAnonymousClass()) return print("this"); + if ((sym.isAnonymousClass() || sym.isCompoundSym()) && !global.debug) + return print("this"); return printSymbolName(sym).print(".this"); case TypeRef(Type pre, Symbol sym, Type[] args): if (sym.isRoot()) return print("<root>"); if (!global.debug) { if (type.isFunctionType()) return printFunctionType(args); - if (sym.isAnonymousClass()) + if (sym.isAnonymousClass() || sym.isCompoundSym()) return printTemplateType(pre.memberInfo(sym).parents()); } printPrefix(pre).printSymbolName(sym); diff --git a/sources/scalac/symtab/Type.java b/sources/scalac/symtab/Type.java index 62db7526e9..7fa877dc82 100644 --- a/sources/scalac/symtab/Type.java +++ b/sources/scalac/symtab/Type.java @@ -22,21 +22,76 @@ public class Type implements Modifiers, Kinds, TypeTags { public case AnyType; // not used after analysis public case NoType; + /** C.this.type + */ public case ThisType(Symbol sym); - public case TypeRef(Type pre, Symbol sym, Type[] args) { - assert pre.isLegalPrefix() || pre == ErrorType : pre + "#" + sym; - } - + /** pre.sym.type + * sym represents a value + */ public case SingleType(Type pre, Symbol sym) { assert this instanceof ExtSingleType; } + /** pre.sym[args] + * sym represents a type + * for example: scala.List[java.lang.String] is coded as + * + * TypeRef( + * SingleType(ThisType(definitions.ROOT_CLASS), definitions.SCALA), + * <List>, + * new Type[]{ + * TypeRef( + * SingleType( + * SingleType(ThisType(definitions.ROOT_CLASS), definitions.JAVA), + * definitions.LANG), + * definitions.STRING, + * new Type[]{})}). + * + */ + public case TypeRef(Type pre, Symbol sym, Type[] args) { + assert pre.isLegalPrefix() || pre == ErrorType : pre + "#" + sym; + } + + /** parts_1 with ... with parts_n { members } + */ public case CompoundType(Type[] parts, Scope members) { assert this instanceof ExtCompoundType; } + + /** synthetic type of a method def ...(vparams): result = ... + */ public case MethodType(Symbol[] vparams, Type result); + + /** synthetic type of a method def ...[tparams]result + * For instance, given def f[a](x: a): a + * f has type PolyType(new Symbol[]{<a>}, + * MethodType(new Symbol[]{<x>}, <a>.type())) + * + * if tparams is empty, this is the type of a parameterless method + * def ... = + * For instance, given def f = 1 + * f has type PolyType(new Symbol[]{}, <scala.Int>.type()) + */ public case PolyType(Symbol[] tparams, Type result); + + /** synthetic type of an overloaded value whose alternatives are + * alts_1, ..., alts_n, with respective types alttypes_1, ..., alttypes_n + * + * For instance, if there are two definitions of `f' + * def f: int + * def f: String + * then there are three symbols: + * ``f1'' corresponding to def f: int + * ``f2'' corresponding to def f: String + * ``f3'' corresponding to both + * f3 has type + * OverloadedType( + * new Symbol[]{<f1>, <f2>}, + * new Type[]{PolyType(new Symbol[]{}, <int>), + * PolyType(new Symbol[]{}, <String>), + * + */ public case OverloadedType(Symbol[] alts, Type[] alttypes); /** Hidden case to implement delayed evaluation of types. @@ -2528,6 +2583,15 @@ public class Type implements Modifiers, Kinds, TypeTags { super(msg); } } + + public static void explainTypes(Type found, Type required) { + if (Global.instance.explaintypes) { + boolean s = explainSwitch; + explainSwitch = true; + found.isSubType(required); + explainSwitch = s; + } + } } /* A standard pattern match: diff --git a/sources/scalac/transformer/LambdaLift.java b/sources/scalac/transformer/LambdaLift.java index fd89c3c260..1e90f95624 100644 --- a/sources/scalac/transformer/LambdaLift.java +++ b/sources/scalac/transformer/LambdaLift.java @@ -197,6 +197,7 @@ public class LambdaLift extends OwnerTransformer public Tree transform(Tree tree) { //if (global.debug) global.debugPrinter.print("free ").print(tree).println().end();//DEBUG + assert tree.type != null : tree; traverseTypeMap.apply(tree.type.widen()); Symbol sym = tree.symbol(); switch(tree) { diff --git a/sources/scalac/transformer/PatternMatcher.java b/sources/scalac/transformer/PatternMatcher.java index d15a6d22a1..3426a52424 100644 --- a/sources/scalac/transformer/PatternMatcher.java +++ b/sources/scalac/transformer/PatternMatcher.java @@ -345,7 +345,7 @@ public class PatternMatcher { protected Tree[] patternArgs(Tree tree) { switch (tree) { case Apply(_, Tree[] args): - if (args.length == 1) + if (args.length == 1 && (tree.type.symbol().flags & Modifiers.CASE) == 0) switch (args[0]) { case Sequence(Tree[] ts): return ts; @@ -378,60 +378,62 @@ public class PatternMatcher { protected PatternNode patternNode(Tree tree, Header header, CaseEnv env) { switch (tree) { - case Apply(Tree fn, Tree[] args): // pattern with args - if (args.length == 1) - switch (args[0]) { - case Sequence(Tree[] ts): - return makeSequencePat(tree.pos, tree.type, ts.length); - } - return makeConstrPat(tree.pos, getConstrType(tree.type)); - case Typed(Ident(Name name), Tree tpe): // variable pattern - PatternNode node = - (header.type.isSubType(getConstrType(tpe.type))) ? - makeDefaultPat(tree.pos, getConstrType(tpe.type)) - : makeConstrPat(tree.pos, getConstrType(tpe.type)); - if ((env != null) && (name != WILDCARD_N)) - switch (node) { - case ConstrPat(Symbol casted): - env.newBoundVar( - tree.pos, - ((Tree.Typed)tree).expr.symbol(), - getConstrType(tpe.type), - make.Ident(tree.pos, casted.name). - setType(typeOf(casted)). - setSymbol(casted)); - break; - default: - env.newBoundVar( - tree.pos, - ((Tree.Typed)tree).expr.symbol(), - getConstrType(tpe.type), - header.selector); - } - return node; - case Ident(Name name): // pattern without args or variable - if (tree.symbol().isPrimaryConstructor()) - return makeConstrPat(tree.pos, getConstrType(tree.type)); - else if (name.isVariable()) { - if ((env != null) && (name != WILDCARD_N)) - env.newBoundVar( - tree.pos, - tree.symbol(), - getConstrType(tree.type), - header.selector); - return makeDefaultPat(tree.pos, getConstrType(header.type)); - } else + case Apply(Tree fn, Tree[] args): // pattern with args + if (args.length == 1 && (tree.type.symbol().flags & Modifiers.CASE) == 0) + switch (args[0]) { + case Sequence(Tree[] ts): + return makeSequencePat(tree.pos, tree.type, ts.length); + } + return makeConstrPat(tree.pos, getConstrType(tree.type)); + case Typed(Ident(Name name), Tree tpe): // variable pattern + PatternNode node = + (header.type.isSubType(getConstrType(tpe.type))) ? + makeDefaultPat(tree.pos, getConstrType(tpe.type)) + : makeConstrPat(tree.pos, getConstrType(tpe.type)); + if ((env != null) && (name != WILDCARD_N)) + switch (node) { + case ConstrPat(Symbol casted): + env.newBoundVar( + tree.pos, + ((Tree.Typed)tree).expr.symbol(), + getConstrType(tpe.type), + make.Ident(tree.pos, casted.name). + setType(typeOf(casted)). + setSymbol(casted)); + break; + default: + env.newBoundVar( + tree.pos, + ((Tree.Typed)tree).expr.symbol(), + getConstrType(tpe.type), + header.selector); + } + return node; + case Ident(Name name): // pattern without args or variable + if (tree.symbol().isPrimaryConstructor()) + return makeConstrPat(tree.pos, getConstrType(tree.type)); + else if (name.isVariable()) { + if ((env != null) && (name != WILDCARD_N)) + env.newBoundVar( + tree.pos, + tree.symbol(), + getConstrType(tree.type), + header.selector); + return makeDefaultPat(tree.pos, getConstrType(header.type)); + } else return makeVariablePat(tree.pos, tree); - case Select(_, Name name): // variable - if (tree.symbol().isPrimaryConstructor()) - return makeConstrPat(tree.pos, getConstrType(tree.type)); - else - return makeVariablePat(tree.pos, tree); - case Literal(Object value): - return makeConstantPat(tree.pos, getConstrType(tree.type), value); - default: - new scalac.ast.printer.TextTreePrinter().print(tree).flush(); - throw new ApplicationError(tree); + case Select(_, Name name): // variable + if (tree.symbol().isPrimaryConstructor()) + return makeConstrPat(tree.pos, getConstrType(tree.type)); + else + return makeVariablePat(tree.pos, tree); + case Literal(Object value): + return makeConstantPat(tree.pos, getConstrType(tree.type), value); + case Sequence(Tree[] ts): + return makeSequencePat(tree.pos, tree.type, ts.length); + default: + new scalac.ast.printer.TextTreePrinter().print(tree).flush(); + throw new ApplicationError(tree); } } diff --git a/sources/scalac/transformer/matching/PatternMatcher.java b/sources/scalac/transformer/matching/PatternMatcher.java index d15a6d22a1..3426a52424 100644 --- a/sources/scalac/transformer/matching/PatternMatcher.java +++ b/sources/scalac/transformer/matching/PatternMatcher.java @@ -345,7 +345,7 @@ public class PatternMatcher { protected Tree[] patternArgs(Tree tree) { switch (tree) { case Apply(_, Tree[] args): - if (args.length == 1) + if (args.length == 1 && (tree.type.symbol().flags & Modifiers.CASE) == 0) switch (args[0]) { case Sequence(Tree[] ts): return ts; @@ -378,60 +378,62 @@ public class PatternMatcher { protected PatternNode patternNode(Tree tree, Header header, CaseEnv env) { switch (tree) { - case Apply(Tree fn, Tree[] args): // pattern with args - if (args.length == 1) - switch (args[0]) { - case Sequence(Tree[] ts): - return makeSequencePat(tree.pos, tree.type, ts.length); - } - return makeConstrPat(tree.pos, getConstrType(tree.type)); - case Typed(Ident(Name name), Tree tpe): // variable pattern - PatternNode node = - (header.type.isSubType(getConstrType(tpe.type))) ? - makeDefaultPat(tree.pos, getConstrType(tpe.type)) - : makeConstrPat(tree.pos, getConstrType(tpe.type)); - if ((env != null) && (name != WILDCARD_N)) - switch (node) { - case ConstrPat(Symbol casted): - env.newBoundVar( - tree.pos, - ((Tree.Typed)tree).expr.symbol(), - getConstrType(tpe.type), - make.Ident(tree.pos, casted.name). - setType(typeOf(casted)). - setSymbol(casted)); - break; - default: - env.newBoundVar( - tree.pos, - ((Tree.Typed)tree).expr.symbol(), - getConstrType(tpe.type), - header.selector); - } - return node; - case Ident(Name name): // pattern without args or variable - if (tree.symbol().isPrimaryConstructor()) - return makeConstrPat(tree.pos, getConstrType(tree.type)); - else if (name.isVariable()) { - if ((env != null) && (name != WILDCARD_N)) - env.newBoundVar( - tree.pos, - tree.symbol(), - getConstrType(tree.type), - header.selector); - return makeDefaultPat(tree.pos, getConstrType(header.type)); - } else + case Apply(Tree fn, Tree[] args): // pattern with args + if (args.length == 1 && (tree.type.symbol().flags & Modifiers.CASE) == 0) + switch (args[0]) { + case Sequence(Tree[] ts): + return makeSequencePat(tree.pos, tree.type, ts.length); + } + return makeConstrPat(tree.pos, getConstrType(tree.type)); + case Typed(Ident(Name name), Tree tpe): // variable pattern + PatternNode node = + (header.type.isSubType(getConstrType(tpe.type))) ? + makeDefaultPat(tree.pos, getConstrType(tpe.type)) + : makeConstrPat(tree.pos, getConstrType(tpe.type)); + if ((env != null) && (name != WILDCARD_N)) + switch (node) { + case ConstrPat(Symbol casted): + env.newBoundVar( + tree.pos, + ((Tree.Typed)tree).expr.symbol(), + getConstrType(tpe.type), + make.Ident(tree.pos, casted.name). + setType(typeOf(casted)). + setSymbol(casted)); + break; + default: + env.newBoundVar( + tree.pos, + ((Tree.Typed)tree).expr.symbol(), + getConstrType(tpe.type), + header.selector); + } + return node; + case Ident(Name name): // pattern without args or variable + if (tree.symbol().isPrimaryConstructor()) + return makeConstrPat(tree.pos, getConstrType(tree.type)); + else if (name.isVariable()) { + if ((env != null) && (name != WILDCARD_N)) + env.newBoundVar( + tree.pos, + tree.symbol(), + getConstrType(tree.type), + header.selector); + return makeDefaultPat(tree.pos, getConstrType(header.type)); + } else return makeVariablePat(tree.pos, tree); - case Select(_, Name name): // variable - if (tree.symbol().isPrimaryConstructor()) - return makeConstrPat(tree.pos, getConstrType(tree.type)); - else - return makeVariablePat(tree.pos, tree); - case Literal(Object value): - return makeConstantPat(tree.pos, getConstrType(tree.type), value); - default: - new scalac.ast.printer.TextTreePrinter().print(tree).flush(); - throw new ApplicationError(tree); + case Select(_, Name name): // variable + if (tree.symbol().isPrimaryConstructor()) + return makeConstrPat(tree.pos, getConstrType(tree.type)); + else + return makeVariablePat(tree.pos, tree); + case Literal(Object value): + return makeConstantPat(tree.pos, getConstrType(tree.type), value); + case Sequence(Tree[] ts): + return makeSequencePat(tree.pos, tree.type, ts.length); + default: + new scalac.ast.printer.TextTreePrinter().print(tree).flush(); + throw new ApplicationError(tree); } } diff --git a/sources/scalac/typechecker/Analyzer.java b/sources/scalac/typechecker/Analyzer.java index 1e8ec9daa9..c4b404cc9a 100644 --- a/sources/scalac/typechecker/Analyzer.java +++ b/sources/scalac/typechecker/Analyzer.java @@ -23,6 +23,8 @@ import scalac.symtab.*; import Tree.*; import java.util.HashMap; +/** The main attribution phase. + */ public class Analyzer extends Transformer implements Modifiers, Kinds { private final Definitions definitions; @@ -131,39 +133,13 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { // expressions may be packages and // Java statics modules. - static final int baseModes = EXPRmode | PATTERNmode | CONSTRmode; - -// Helper definitions --------------------------------------------------------- + static final int SUPERmode = 0x080; // orthogonal to above. When set + // we are checking a superclass + // constructor invocation. - /** 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.typeOfThis(); - break; - } - return fn.type == Type.ErrorType ? Type.ErrorType : Type.NoType; - } + static final int baseModes = EXPRmode | PATTERNmode | CONSTRmode; - private Type value2Type(Object value) { - if (value instanceof Character) return definitions.CHAR_TYPE; - else if (value instanceof Integer) return definitions.INT_TYPE; - else if (value instanceof Long) return definitions.LONG_TYPE; - else if (value instanceof Float) return definitions.FLOAT_TYPE; - else if (value instanceof Double) return definitions.DOUBLE_TYPE; - else if (value instanceof String) return definitions.JAVA_STRING_TYPE; - else if (value instanceof Boolean) return definitions.BOOLEAN_TYPE; - else throw new ApplicationError(); - } +// Diagnostics ---------------------------------------------------------------- Tree errorTree(int pos) { return make.Bad(pos).setSymbol(Symbol.ERROR).setType(Type.ErrorType); @@ -174,14 +150,6 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { return errorTree(pos); } - void explainTypes(Type found, Type required) { - if (global.explaintypes) { - Type.explainSwitch = true; - found.isSubType(required); - Type.explainSwitch = false; - } - } - void typeError(int pos, Type found, Type req) { String msg = infer.typeErrorMsg("type mismatch", found, req); Type foundResult = found.resultType(); @@ -266,7 +234,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { * - no conflicting modifiers * - `abstract' modifier only for classes * - `override' modifier never for classes - * - def and `*' modifiers only in methods + * - `def' modifier never for parameters of case classes * - declarations only in traits or abstract classes * - symbols with `override' modifier override some other symbol. */ @@ -283,18 +251,23 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { if ((sym.flags & OVERRIDE) != 0 && sym.kind == CLASS) { 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"); + if ((sym.flags & DEF) != 0 && sym.owner().isPrimaryConstructor() && + (sym.owner().primaryConstructorClass().flags & CASE) != 0) { + error(sym.pos, "`def' modifier not allowed for case class parameters"); } + /*!!! if ((sym.flags & REPEATED) != 0 && sym.owner().isPrimaryConstructor()) { error(sym.pos, "`*' modifier not allowed for class parameters"); } + */ if ((sym.flags & DEFERRED) != 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")); + error(sym.pos, + "only classes can have declared but undefined members" + + (((sym.flags & MUTABLE) == 0) ? "" + : "\n(Note that variables need to be initialized to be defined)")); sym.flags &= ~DEFERRED; } } @@ -571,206 +544,128 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { } } - /** 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 && (other.flags & PRIVATE) == 0 && - member.kind != NONE) - checkOverride(clazz, member, other); - if ((member.flags & DEFERRED) != 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. + /** Check that all subtrees have their types defined. + * Used for asserting an internal invariant */ - 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, "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)) { - overrideError(pos, member, other, "needs `override' modifier"); - } else if (other.isStable() && !member.isStable()) { - overrideError(pos, member, other, "needs to be an immutable value"); - } else { - Type self = clazz.thisType(); - switch (other.kind) { - case CLASS: - overrideError(pos, member, other, "cannot override a class"); - break; - case ALIAS: - 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"); - Type selftype = normalizedInfo(self, member); - Type othertype = normalizedInfo(self, other); - if (!selftype.isSubType(othertype)) - overrideTypeError(pos, member, other, self, false); - if (member.kind == TYPE && - !self.memberLoBound(other).isSubType( - self.memberLoBound(member))) - overrideTypeError(pos, member, other, self, true); - - } + private static class CheckDefined extends Traverser { + Tree all; + public void traverse(Tree tree) { + assert tree.type != null : tree + " in " + all; + if (tree.type != Type.ErrorType) + super.traverse(tree); } } - 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() + - ";\n " + member + member.locationString() + " " + msg); - } - - 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, memberInfo, lobound) + - "\n cannot override " + other + other.locationString() + - infoString(other, otherInfo, lobound)); - explainTypes(memberInfo, otherInfo); - } - } + private static CheckDefined checkDefined = new CheckDefined(); - Type normalizedInfo(Type site, Symbol sym) { - Type tp = site.memberInfo(sym); - if (sym.kind == VAL && (sym.flags & STABLE) != 0) tp = tp.resultType(); - return tp; - } +// Helper definitions for calculating types ----------------------------------------- - String infoString(Symbol sym, Type symtype, boolean lobound) { - switch (sym.kind) { - case ALIAS: return ", which equals " + symtype; - case TYPE: return " bounded" + (lobound ? " from below" : "") + " by " + symtype; - case VAL: return " of type " + symtype; - default: return ""; + /** 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.typeOfThis(); + break; } + return fn.type == Type.ErrorType ? Type.ErrorType : Type.NoType; } - 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; + private Type value2Type(Object value) { + if (value instanceof Character) return definitions.CHAR_TYPE; + else if (value instanceof Integer) return definitions.INT_TYPE; + else if (value instanceof Long) return definitions.LONG_TYPE; + else if (value instanceof Float) return definitions.FLOAT_TYPE; + else if (value instanceof Double) return definitions.DOUBLE_TYPE; + else if (value instanceof String) return definitions.JAVA_STRING_TYPE; + else if (value instanceof Boolean) return definitions.BOOLEAN_TYPE; + else throw new ApplicationError(); } -// Variance Checking -------------------------------------------------------- - - private final int - ContraVariance = -1, - NoVariance = 0, - CoVariance = 1, - AnyVariance = 2; +// Contexts ------------------------------------------------------------------- - private String varianceString(int variance) { - if (variance == 1) return "covariant"; - else if (variance == -1) return "contravariant"; - else return "invariant"; + /** 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); } - /** The variance of symbol `base' relative to the class which defines `tvar'. + /** Pop context from stack. */ - int flip(Symbol base, Symbol tvar) { - Symbol clazz = tvar.owner().primaryConstructorClass(); - Symbol sym = base; - int flip = CoVariance; - while (sym != clazz && flip != AnyVariance) { - //System.out.println("flip: " + sym + " " + sym.isParameter());//DEBUG - if (sym.isParameter()) flip = -flip; - else if (sym.owner().kind != CLASS) flip = AnyVariance; - else if (sym.kind == ALIAS) flip = NoVariance; - sym = sym.owner(); - } - return flip; + void popContext() { + context = context.outer; } - /** Check variance of type variables in this type +// Lazy Types ------------------------------------------------------------------ + + /** A lazy type which, when forced returns the type of a symbol defined + * in `tree'. */ - void validateVariance(Symbol base, Type tp, int variance) { - validateVariance(base, tp, tp, variance); + class LazyTreeType extends Type.LazyType { + Tree tree; + Unit u; + Context c; + + LazyTreeType(Tree tree) { + this.tree = tree; + this.u = unit; + this.c = context; + } + public void complete(Symbol sym) { + //System.out.println("completing " + sym);//DEBUG + //if (sym.isConstructor()) sym.constructorClass().initialize(); + //else if (sym.isModule()) sym.moduleClass().initialize(); + defineSym(tree, u, c); + } } - void validateVariance(Symbol base, Type all, Type tp, int variance) { - switch (tp) { - case ErrorType: - case AnyType: - case NoType: - case ThisType(Symbol sym): - break; - case SingleType(Type pre, Symbol sym): - validateVariance(base, all, pre, variance); - break; - case TypeRef(Type pre, Symbol sym, Type[] args): - if (sym.variance() != 0) { - int f = flip(base, sym); - if (f != AnyVariance && sym.variance() != f * variance) { - //System.out.println("flip(" + base + "," + sym + ") = " + f);//DEBUG - error(base.pos, - varianceString(sym.variance()) + " " + sym + - " occurs in " + varianceString(f * variance) + - " position in type " + all + " of " + base); + /** 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) { + Type constrtype = tree.symbol().constructor().type().instanceType(); + switch (tree) { + case ClassDef(_, _, _, ValDef[][] vparams, _, _): + if (vparams.length == 0) { + constrtype = removeMethod(constrtype); } } - validateVariance(base, all, pre, variance); - validateVariance(base, all, args, variance, sym.typeParams()); - break; - case CompoundType(Type[] parts, Scope members): - validateVariance(base, all, parts, variance); - break; - case MethodType(Symbol[] vparams, Type result): - validateVariance(base, all, result, variance); - break; - case PolyType(Symbol[] tparams, Type result): - validateVariance(base, all, result, variance); - break; - case OverloadedType(Symbol[] alts, Type[] alttypes): - validateVariance(base, all, alttypes, variance); + sym.setInfo(constrtype); + } + private Type removeMethod(Type tp) { + switch (tp) { + case MethodType(_, Type restp): + return restp; + case PolyType(Symbol[] tparams, Type restp): + return Type.PolyType(tparams, removeMethod(restp)); + default: + return tp; + } } } - void validateVariance(Symbol base, Type all, Type[] tps, int variance) { - for (int i = 0; i < tps.length; i++) - validateVariance(base, all, tps[i], variance); - } - - void validateVariance(Symbol base, Type all, Type[] tps, int variance, Symbol[] tparams) { - for (int i = 0; i < tps.length; i++) - validateVariance(base, all, tps[i], variance * tparams[i].variance()); + /** A lazy type for self types + */ + class LazySelfType extends LazyTreeType { + LazySelfType(Tree tree) { + super(tree); + } + public void complete(Symbol sym) { + defineSelfType(sym, tree, u, c); + } } // Entering Symbols ---------------------------------------------------------- @@ -966,6 +861,42 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { enterSym(stats[i]); } + Symbol[] enterParams(Tree[] params) { + for (int i = 0; i < params.length; i++) { + enterSym(params[i]); + switch (params[i]) { + case ValDef(int mods, _, _, _): + if ((mods & REPEATED) != 0 && params.length > 1) + error(params[i].pos, + "`*' parameter must be the only parameter of a `('...`)' section"); + } + } + 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; + } + + /** 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]); + } + // Definining Symbols ------------------------------------------------------- /** Define symbol associated with `tree' using given `unit' and `context'. @@ -986,12 +917,6 @@ 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); - } - ((ClassDef) tree).mods |= LOCKED; pushContext(tree, sym.constructor(), new Scope(context.scope)); Symbol[] tparamSyms = enterParams(tparams); Symbol[][] vparamSyms = enterParams(vparams); @@ -1021,12 +946,14 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { Symbol clazz = sym.moduleClass(); defineTemplate(templ, clazz); clazz.setInfo(templ.type); - if (tpe == Tree.Empty) owntype = clazz.type(); - else owntype = transform(tpe, TYPEmode).type; + ((ModuleDef) tree).tpe = tpe = transform(tpe, TYPEmode); + owntype = (tpe == Tree.Empty) ? clazz.type() : tpe.type; break; case ValDef(int mods, Name name, Tree tpe, Tree rhs): - if (tpe == Tree.Empty) { + if (tpe != Tree.Empty) { + ((ValDef) tree).tpe = tpe = transform(tpe, TYPEmode); + } else { pushContext(tree, sym, context.scope); if (rhs == Tree.Empty) { if ((sym.owner().flags & ACCESSOR) != 0) { @@ -1039,20 +966,13 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { ((ValDef) tree).tpe = tpe = gen.mkType(tree.pos, Type.ErrorType); } - owntype = tpe.type; } else { - if ((mods & CASEACCESSOR) != 0) { - //rhs was already attributed - assert rhs.type != null; - } else { - ((ValDef) tree).rhs = rhs = transform(rhs, EXPRmode); - } - owntype = rhs.type; + ((ValDef) tree).rhs = rhs = transform(rhs, EXPRmode); + ((ValDef) tree).tpe = tpe = gen.mkType(tree.pos, rhs.type); } popContext(); - } else { - owntype = transform(tpe, TYPEmode).type; } + owntype = tpe.type; checkNonCyclic(tree.pos, owntype); break; @@ -1060,43 +980,41 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { pushContext(tree, sym, new Scope(context.scope)); Symbol[] tparamSyms = enterParams(tparams); Symbol[][] vparamSyms = enterParams(vparams); - Type restpe; - if (tpe == Tree.Empty) { + if (tpe != Tree.Empty) { + ((DefDef) tree).tpe = tpe = transform(tpe, TYPEmode); + } else { int rhsmode = name.isConstrName() ? CONSTRmode : EXPRmode; ((DefDef) tree).rhs = rhs = transform(rhs, rhsmode); - restpe = checkNoEscape(rhs.pos, rhs.type); - } else { - restpe = checkNoEscape( - tpe.pos, transform(tpe, TYPEmode).type); + ((DefDef) tree).tpe = tpe = gen.mkType(tree.pos, rhs.type); } + Type restype = checkNoEscape(tpe.pos, tpe.type); popContext(); - checkNonCyclic(tree.pos, restpe); - owntype = makeMethodType(tparamSyms, vparamSyms, restpe); + checkNonCyclic(tree.pos, restype); + owntype = makeMethodType(tparamSyms, vparamSyms, restype); //System.out.println("methtype " + name + ":" + owntype);//DEBUG break; case TypeDef(int mods, Name name, Tree rhs, Tree lobound): 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; - sym.setLoBound(transform(lobound, TYPEmode).type); - owntype.symbol().initialize();//to detect cycles - popContext(); + //can't have `sym' as owner since checkNonCyclic would fail. + ((TypeDef) tree).rhs = rhs = transform(rhs, TYPEmode); + ((TypeDef) tree).lobound = lobound = transform(lobound, TYPEmode); + owntype = rhs.type; + sym.setLoBound(lobound.type); + owntype.symbol().initialize();//to detect cycles todo: needed? } else { // sym.kind == ALIAS pushContext(tree, sym, context.scope); - owntype = transform(rhs, TYPEmode | FUNmode).type; + ((TypeDef) tree).rhs = rhs = transform(rhs, TYPEmode | FUNmode); + owntype = rhs.type; popContext(); } checkNonCyclic(tree.pos, owntype); break; case Import(Tree expr, Name[] selectors): - Tree expr1 = transform(expr, EXPRmode | QUALmode); - ((Import) tree).expr = expr1; - checkStable(expr1); - owntype = expr1.type; + ((Import) tree).expr = expr = transform(expr, EXPRmode | QUALmode); + checkStable(expr); + owntype = expr.type; break; default: @@ -1122,13 +1040,8 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { */ void defineTemplate(Tree.Template templ, Symbol clazz) { // attribute parent constructors - Tree[] constrs = transformConstrInvocations( - templ.pos, templ.parents, true); - - Type[] parents = new Type[constrs.length]; - for (int i = 0; i < parents.length; i++) { - parents[i] = constrs[i].type; - } + Tree[] constrs = transformConstrInvocations(templ.pos, templ.parents); + Type[] parents = Tree.typeOf(constrs); // enter all members Scope members = new Scope(); @@ -1136,31 +1049,9 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { templ.body = desugarize.Statements(templ.body, false); enterSyms(templ.body); popContext(); - templ.type = Type.compoundType(parents, members, clazz); } - Symbol[] enterParams(Tree[] params) { - for (int i = 0; i < params.length; i++) { - enterSym(params[i]); - switch (params[i]) { - case ValDef(int mods, _, _, _): - if ((mods & REPEATED) != 0 && params.length > 1) - error(params[i].pos, - "`*' parameter must be the only parameter of a `('...`)' section"); - } - } - 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); @@ -1174,7 +1065,6 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { } } - Tree makeStableId(int pos, Type tp) { if (tp.symbol().isCompoundSym()) return make.This(pos, Tree.Empty).setType(tp); @@ -1182,21 +1072,6 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { return gen.mkStableId(pos, tp); } - /** 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]); - } - /** Define self type of class or module `sym' * associated with `tree' using given `unit' and `context'. */ @@ -1214,6 +1089,147 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { // Attribution and Transform ------------------------------------------------- + /** Adapt tree to given mode and given prototype + */ + 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.pos, 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) { + tree = error(tree.pos, ex.msg); + } + return adapt(tree, mode, pt); + } + 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.pos, "missing arguments for class constructor"); + } + } + if ((mode & PATTERNmode) != 0) { + if (tree.isType()) { + Symbol clazz = tree.type.unalias().symbol(); + if (clazz.isCaseClass()) { + // set type to instantiated case class constructor + 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); + return tree.setType(Type.ErrorType); + } +/* + if (!(tree.type instanceof Type.MethodType)) + tree = make.Apply(tree.pos, tree, Tree.EMPTY_ARRAY) + .setType(tree.type); +*/ + } + } else if (clazz.isSubClass(definitions.SEQ_CLASS)) { + // set type to instantiated sequence class constructor + // todo: should we admit even supertypes of the target type? + Type seqtp = pt.baseType(clazz); + if (seqtp != Type.NoType) { + tree.type = seqConstructorType(seqtp, pt); + } else { + error(tree.pos, "expected pattern type " + pt + + " does not conform to sequence " + clazz); + } + } else if (tree.type != Type.ErrorType) { + error(tree.pos, tree.type.symbol() + + " is neither a case class constructor nor a sequence class constructor"); + } + } + if ((mode & FUNmode) != 0) { + return tree; + } else { + Symbol sym = tree.symbol(); + // check that idents or selects are stable. + switch (tree) { + case Ident(_): + case Select(_, _): + checkStable(tree); + } + } + } else if ((mode & EXPRmode) != 0) { + if ((mode & FUNmode) != 0) { + if (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) == 0) { + // check that packages and static modules are not used as values + Symbol sym = tree.symbol(); + if (tree.isTerm() && + sym != null && sym.kind != ERROR && !sym.isValue()) { + error(tree.pos, tree.symbol() + " is not a value"); + } + } + } + + Type owntype = tree.type; + if ((mode & (CONSTRmode | FUNmode)) == (CONSTRmode)) { + owntype = owntype.instanceType(); + // this works as for superclass constructor calls the expected + // type `pt' is always AnyType (see transformConstrInvocations). + } + if (!(owntype instanceof Type.PolyType || owntype.isSubType(pt))) { + typeError(tree.pos, owntype, pt); + Type.explainTypes(owntype, pt); + tree.type = Type.ErrorType; + } + return tree; + } + //where + Type seqConstructorType(Type paramtp, Type resulttp) { + Symbol constr = resulttp.symbol().constructor(); + Symbol param = new TermSymbol( + Position.NOPOS, Names.WILDCARD, constr, PARAM | REPEATED).setInfo( + paramtp.baseType(definitions.SEQ_CLASS)); + return Type.MethodType(new Symbol[]{param}, resulttp); + } + /** 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. @@ -1354,14 +1370,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { sym.isStable() && qual.type.isStable()) symtype = Type.singleType(qual.type, sym); //System.out.println(qual.type + ".member: " + sym + ":" + symtype);//DEBUG - switch (tree) { - case Select(_, _): - return copy.Select(tree, sym, qual).setType(symtype); - case SelectFromType(_, _): - return make.TypeTerm(tree.pos).setType(symtype); - default: - throw new ApplicationError(); - } + return copy.Select(tree, sym, qual).setType(symtype); } } @@ -1412,7 +1421,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { } Tree stat1; int mode = TreeInfo.isDefinition(stat) ? NOmode : EXPRmode; - if (exprOwner.kind != NONE && !TreeInfo.isOwnerDefinition(stat)) { + if (exprOwner.kind != NONE && !TreeInfo.isDefinition(stat)) { pushContext(stat, exprOwner, context.scope); stat1 = transform(stat, mode); popContext(); @@ -1432,47 +1441,56 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { /** Attribute a sequence of constructor invocations. */ - Tree[] transformConstrInvocations(int pos, Tree[] constrs, boolean delayArgs) { + Tree[] transformConstrInvocations(int pos, Tree[] constrs) { for (int i = 0; i < constrs.length; i++) { - pushContext(constrs[i], context.owner, context.scope); - context.delayArgs = delayArgs; - constrs[i] = transform(constrs[i], CONSTRmode, Type.AnyType); + //!!!pushContext(constrs[i], context.owner, context.scope); + constrs[i] = transform(constrs[i], CONSTRmode | SUPERmode, Type.AnyType); Symbol f = TreeInfo.methSymbol(constrs[i]); if (f != null) { Symbol c = f.primaryConstructorClass(); if (c.kind == CLASS) c.initialize();//to detect cycles } - popContext(); + //!!!popContext(); } return constrs; } + void transformConstrInvocationArgs(Tree[] constrs) { + for (int i = 0; i < constrs.length; i++) { + switch (constrs[i]) { + case Apply(Tree fn, Tree[] args): + if (fn.type instanceof Type.MethodType) + transformArgs( + constrs[i].pos, TreeInfo.methSymbol(fn), Symbol.EMPTY_ARRAY, + fn.type, EXPRmode, args, Type.AnyType); + } + } + } + /** Attribute a template */ public Tree.Template transformTemplate(Tree.Template templ, Symbol owner) { if (global.debug) global.log("transforming " + owner);//debug //System.out.println(owner.info());//DEBUG - Tree[] parents1 = transformConstrInvocations( - templ.pos, templ.parents, false); + Tree[] parents = templ.parents; + transformConstrInvocationArgs(parents); if (owner.kind != ERROR) { - validateParentClasses( - templ.parents, owner.info().parents(), owner.typeOfThis()); + validateParentClasses(parents, owner.info().parents(), owner.typeOfThis()); 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++) { - checkPureConstr(parents1[i], owner); - if (i >= 1) checkTrait(parents1[i], owner); + for (int i = 0; i < parents.length; i++) { + checkPureConstr(parents[i], owner); + if (i >= 1) checkTrait(parents[i], owner); } for (int i = 0; i < templ.body.length; i++) checkPureDef(body1[i], owner); } - Tree.Template templ1 = copy.Template(templ, parents1, body1); + Tree.Template templ1 = copy.Template(templ, parents, body1); templ1.setType(owner.type()); return templ1; } @@ -1582,142 +1600,6 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { 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.pos, 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) { - tree = error(tree.pos, ex.msg); - } - return adapt(tree, mode, pt); - } - 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.pos, "missing arguments for class constructor"); - } - } - if ((mode & PATTERNmode) != 0) { - if (tree.isType()) { - Symbol clazz = tree.type.unalias().symbol(); - if (clazz.isCaseClass()) { - // set type to instantiated case class constructor - 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); - return tree.setType(Type.ErrorType); - } -/* - if (!(tree.type instanceof Type.MethodType)) - tree = make.Apply(tree.pos, tree, Tree.EMPTY_ARRAY) - .setType(tree.type); -*/ - } - } else if (clazz.isSubClass(definitions.SEQ_CLASS)) { - // set type to instantiated sequence class constructor - // todo: should we admit even supertypes of the target type? - Type seqtp = pt.baseType(clazz); - if (seqtp != Type.NoType) { - tree.type = seqConstructorType(seqtp, pt); - } else { - error(tree.pos, "expected pattern type " + pt + - " does not conform to sequence " + clazz); - } - } else if (tree.type != Type.ErrorType) { - error(tree.pos, tree.type.symbol() + - " is neither a case class constructor nor a sequence class constructor"); - } - } - if ((mode & FUNmode) != 0) { - return tree; - } else { - Symbol sym = tree.symbol(); - // check that idents or selects are stable. - switch (tree) { - case Ident(_): - case Select(_, _): - checkStable(tree); - } - } - } else if ((mode & EXPRmode) != 0) { - if ((mode & FUNmode) != 0) { - if (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) == 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"); - } - } - } - - Type owntype = tree.type; - if ((mode & (CONSTRmode | FUNmode)) == (CONSTRmode)) - owntype = owntype.instanceType(); - if (!(owntype instanceof Type.PolyType || owntype.isSubType(pt))) { - typeError(tree.pos, owntype, pt); - explainTypes(owntype, pt); - tree.type = Type.ErrorType; - } - return tree; - } - //where - Type seqConstructorType(Type paramtp, Type resulttp) { - Symbol constr = resulttp.symbol().constructor(); - Symbol param = new TermSymbol( - Position.NOPOS, Names.WILDCARD, constr, PARAM | REPEATED).setInfo( - paramtp); - return Type.MethodType(new Symbol[]{param}, resulttp); - } - /** Transform expression or type with a given mode. */ public Tree transform(Tree tree, int mode) { @@ -1730,6 +1612,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { this.mode = savedMode; if ((mode & TYPEmode) != 0) { + // todo: generalize to type constructors? Symbol sym = tree1.symbol(); if ((mode & FUNmode) == 0 && sym != null && sym.typeParams().length != 0) return error(tree.pos, sym + " takes type parameters."); @@ -1748,7 +1631,11 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { /** The main attribution function */ public Tree transform(Tree tree) { - //new TextTreePrinter().print("transforming ").print(tree).println().end();//DEBUG + //System.out.println("transforming " + tree);//DEBUG + if (tree.type != null) { + checkDefined.all = tree; checkDefined.traverse(tree);//debug + return tree; + } Symbol sym = tree.symbol(); if (sym != null && !sym.isInitialized()) sym.initialize(); if (global.debug && TreeInfo.isDefinition(tree)) global.log("transforming " + sym); @@ -1787,38 +1674,22 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { Tree tpe1 = transform(tpe); Tree.Template templ1 = transformTemplate(templ, sym); popContext(); - validateVariance(sym, sym.info(), CoVariance); - validateVariance(sym, sym.typeOfThis(), CoVariance); return copy.ClassDef(tree, sym, tparams1, vparams1, tpe1, templ1) .setType(definitions.UNIT_TYPE); case ModuleDef(_, _, Tree tpe, Tree.Template templ): - Tree tpe1 = transform(tpe, TYPEmode); Tree.Template templ1 = transformTemplate(templ, sym.moduleClass()); - validateVariance(sym.moduleClass(), sym.type(), CoVariance); - validateVariance(sym.moduleClass(), sym.moduleClass().info(), CoVariance); - return copy.ModuleDef(tree, sym, tpe1, templ1) + return copy.ModuleDef(tree, sym, tpe, templ1) .setType(definitions.UNIT_TYPE); case ValDef(_, _, Tree tpe, Tree rhs): - Tree tpe1 = transform(tpe, TYPEmode); Tree rhs1 = rhs; - if (tpe1 == Tree.Empty) { - tpe1 = gen.mkType(rhs.pos, rhs.type); - // rhs already attributed by defineSym in this case - } else if (rhs != Tree.Empty) { - if ((sym.flags & CASEACCESSOR) != 0) { - //rhs was already attributed - } else { - pushContext(tree, sym, context.scope); - rhs1 = transform(rhs, EXPRmode, sym.type()); - popContext(); - } + if (rhs != Tree.Empty) { + pushContext(tree, sym, context.scope); + rhs1 = transform(rhs, EXPRmode, tpe.type); + popContext(); } - validateVariance( - sym, sym.type(), - ((sym.flags & MUTABLE) != 0) ? NoVariance : CoVariance); - return copy.ValDef(tree, sym, tpe1, rhs1) + return copy.ValDef(tree, sym, tpe, rhs1) .setType(definitions.UNIT_TYPE); case DefDef(_, _, Tree.TypeDef[] tparams, Tree.ValDef[][] vparams, Tree tpe, Tree rhs): @@ -1827,34 +1698,15 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { Tree.TypeDef[] tparams1 = transform(tparams); reenterParams(vparams); Tree.ValDef[][] vparams1 = transform(vparams); - Tree tpe1 = transform(tpe, TYPEmode); Tree rhs1 = rhs; - if (tpe1 == Tree.Empty) { - tpe1 = gen.mkType(rhs1.pos, rhs1.type); - //System.out.println("infer " + sym + ":" + rhs.type);//DEBUG - //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); - } + if (rhs != Tree.Empty) + rhs1 = transform(rhs, EXPRmode, tpe.type); popContext(); - validateVariance(sym, sym.type(), CoVariance); - return copy.DefDef(tree, sym, tparams1, vparams1, tpe1, rhs1) + return copy.DefDef(tree, sym, tparams1, vparams1, tpe, rhs1) .setType(definitions.UNIT_TYPE); - case TypeDef(_, _, Tree rhs, Tree lobound): - pushContext(tree, sym, new Scope(context.scope)); - int mode = TYPEmode; - int variance = CoVariance; - if (sym.kind == ALIAS) { - mode |= FUNmode; - variance = NoVariance; - } - Tree rhs1 = transform(rhs, mode); - Tree lobound1 = transform(lobound, TYPEmode); - popContext(); - validateVariance(sym, sym.info(), variance); - return copy.TypeDef(tree, sym, rhs1, lobound1) + case TypeDef(_, _, _, _): + return tree .setType(definitions.UNIT_TYPE); case Import(Tree expr, Name[] selectors): @@ -1869,29 +1721,33 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { context.imports = context.outer.imports; for (int i = 0; i < stats1.length - 1; i++) stats1[i] = transform(stats1[i], EXPRmode); - Type tp; + Type owntype; if (stats1.length > 0) { stats1[stats1.length - 1] = transform(stats1[stats1.length - 1], lastmode, pt); - tp = checkNoEscape(tree.pos, stats1[stats1.length - 1].type); + owntype = checkNoEscape(tree.pos, stats1[stats1.length - 1].type); } else { - tp = definitions.UNIT_TYPE; + owntype = definitions.UNIT_TYPE; } popContext(); return copy.Block(tree, stats1) - .setType(tp); + .setType(owntype); case Visitor(Tree.CaseDef[] cases): if (pt.symbol().isSubClass(definitions.PARTIALFUNCTION_CLASS)) { Type pft = pt.baseType(definitions.PARTIALFUNCTION_CLASS); Type[] pftargs = pft.typeArgs(); - if (pft.typeArgs().length == 2 && infer.isFullyDefined(pftargs[0])) { - Type pattpe = pftargs[0]; - Type restpe = pftargs[1]; - Tree tree1 = transformVisitor(tree, pattpe, restpe); - if (!infer.isFullyDefined(restpe)) restpe = tree1.type; - return transform( - desugarize.partialFunction(tree, pattpe, restpe)); + if (pftargs.length == 2 && infer.isFullyDefined(pftargs[0])) { + Type pattype = pftargs[0]; + Type restype = pftargs[1]; + Tree isDefinedAtVisitor = transformVisitor( + desugarize.isDefinedAtVisitor(tree), + pattype, definitions.BOOLEAN_TYPE); + Tree applyVisitor = transformVisitor(tree, pattype, restype); + if (!infer.isFullyDefined(restype)) restype = applyVisitor.type; + return gen.mkPartialFunction( + tree.pos, applyVisitor, isDefinedAtVisitor, + pattype, restype, context.owner); } else { return error(tree.pos, "expected pattern type of cases could not be determined"); } @@ -1899,7 +1755,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { return transform(desugarize.Visitor(tree)); } - case Assign(Apply(Tree funarray, Tree[] vparam), Tree rhs): + case Assign(Apply(_, _), _): return transform(desugarize.Update(tree)); case Assign(Tree lhs, Tree rhs): @@ -1917,29 +1773,27 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { case If(Tree cond, Tree thenp, Tree elsep): Tree cond1 = transform(cond, EXPRmode, definitions.BOOLEAN_TYPE); + Tree thenp1, elsep1; 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) + thenp1 = transform(thenp, EXPRmode, definitions.UNIT_TYPE); + elsep1 = make.Block(tree.pos, Tree.EMPTY_ARRAY) .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})); + thenp1 = transform(thenp, EXPRmode, pt); + 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); + Type owntype = parent1.type; Tree.Template templ1 = (Tree.Template) copy.Template(templ, Symbol.NONE, new Tree[]{parent1}, body) - .setType(parent1.type); - Type owntype = parent1.type; + .setType(owntype); checkInstantiatable(tree.pos, owntype); return copy.New(tree, templ1) .setType(owntype.instanceType()); @@ -1963,7 +1817,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { Type[] parentTypes = clazz.info().parents(); Scope refinement = new Scope(); Type base = Type.compoundType(parentTypes, Scope.EMPTY); - Type tp = Type.compoundType( + Type owntype = Type.compoundType( parentTypes, refinement, clazz); Scope.SymbolIterator it = clazz.members().iterator(); while (it.hasNext()) { @@ -1976,21 +1830,19 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { } if (refinement.elems == Scope.Entry.NONE && parentTypes.length == 1) - tp = parentTypes[0]; + owntype = parentTypes[0]; else - tp = checkNoEscape(tree.pos, tp); - - Tree alloc = - gen.Typed( - gen.New( - gen.Apply( - gen.mkRef(tree.pos, - Type.localThisType, clazz.constructor()), - Tree.EMPTY_ARRAY)), - tp); + owntype = checkNoEscape(tree.pos, owntype); + + Tree alloc = gen.New( + gen.Apply( + gen.mkRef(tree.pos, + Type.localThisType, clazz.constructor()), + Tree.EMPTY_ARRAY)) + .setType(owntype); popContext(); return make.Block(tree.pos, new Tree[]{cd, alloc}) - .setType(tp); + .setType(owntype); } default: throw new ApplicationError(); @@ -1999,18 +1851,18 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { case Typed(Tree expr, Tree tpe): Tree tpe1 = transform(tpe, TYPEmode); Tree expr1 = transform(expr, mode & baseModes, tpe1.type); - return copy.Typed(tree, expr1, tpe1) - .setType(tpe1.type); + return copy.Typed(tree, expr1, tpe1).setType(tpe1.type); case Function(Tree.ValDef[] vparams, Tree body): pushContext(tree, context.owner, new Scope(context.scope)); Type restype = desugarize.preFunction(vparams, pt); enterParams(vparams); + Tree.ValDef[] vparams1 = transform(vparams); Tree body1 = transform(body, EXPRmode, restype); if (!infer.isFullyDefined(restype)) restype = body1.type; popContext(); - Tree tree1 = copy.Function(tree, vparams, body1); - return transform(desugarize.Function(tree1, restype)); + return gen.mkFunction( + tree.pos, vparams1, body1, restype, context.owner); case TypeApply(Tree fn, Tree[] args): Tree fn1 = transform(fn, EXPRmode | FUNmode, Type.AnyType); @@ -2030,20 +1882,9 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { // 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)) && - tparams[i].loBound().subst(tparams, argtypes) - .isSubType(argtypes[i])))) - i++; - if (i == tparams.length) { - return copy.TypeApply(tree, fn1, args1) - .setType(restp.subst(tparams, argtypes)); - } - } + if (tparams.length == argtypes.length) + return copy.TypeApply(tree, fn1, args1) + .setType(restp.subst(tparams, argtypes)); break; case ErrorType: return tree.setType(Type.ErrorType); @@ -2110,14 +1951,10 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { } } - // 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); - } - } + // return prematurely if function is a superclass constructor + // and no type arguments need to be inferred. + if ((mode & SUPERmode) != 0 && fn1.type instanceof Type.MethodType) + return copy.Apply(tree, fn1, args).setType(fn1.type.resultType()); // type arguments with formals as prototypes if they exist. fn1.type = infer.freshInstance(fn1.type); @@ -2150,6 +1987,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { // infer instance, and adapt arguments to instantiated formals try { fn1 = infer.methodInstance(fn1, tparams, restp, argtypes, pt); + //System.out.println(fn1 + ":" + fn1.type);//DEBUG } catch (Type.Error ex) { error(tree.pos, ex.msg); } @@ -2258,7 +2096,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { case SingletonType(Tree ref): Tree ref1 = transform(ref, EXPRmode | QUALmode, Type.AnyType); - return make.TypeTerm(tree.pos) + return copy.SingletonType(tree, ref1) .setType(checkObjectType(tree.pos, ref1.type.resultType())); case SelectFromType(Tree qual, Name name): @@ -2277,9 +2115,8 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { enterSym(refinements[i]).flags |= OVERRIDE; } Tree[] refinements1 = transformStatSeq(refinements, Symbol.NONE); - checkAllOverrides(clazz); popContext(); - return make.TypeTerm(tree.pos) + return copy.CompoundType(tree, parents1, refinements1) .setType(self); case AppliedType(Tree tpe, Tree[] args): @@ -2293,25 +2130,14 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { : Symbol.EMPTY_ARRAY; Type owntype = Type.ErrorType; if (tpe1.type != Type.ErrorType) { - if (tparams.length == args.length) { - try { - if (!context.delayArgs) - infer.checkBounds(tparams, argtypes, ""); - owntype = Type.appliedType(tpe1.type, argtypes); - } catch (Type.Error ex) { - error(tree.pos, ex.msg); - } - } else { - if (tparams.length == 0) - error(tree.pos, tpe1.type + - " does not take type parameters"); - else - error(tree.pos, - "wrong number of type arguments for " + - tpe1.type); - } + if (tparams.length == args.length) + owntype = Type.appliedType(tpe1.type, argtypes); + else if (tparams.length == 0) + error(tree.pos, tpe1.type + " does not take type parameters"); + else error(tree.pos, "wrong number of type arguments for " + + tpe1.type); } - return make.TypeTerm(tree.pos).setType(owntype); + return copy.AppliedType(tree, tpe1, args1).setType(owntype); case FunType(_, _): return transform(desugarize.FunType(tree)); @@ -2326,83 +2152,5 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { return tree; } } - -// 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; - Context c; - - LazyTreeType(Tree tree) { - this.tree = tree; - this.u = unit; - this.c = context; - } - public void complete(Symbol sym) { - //System.out.println("completing " + sym);//DEBUG - //if (sym.isConstructor()) sym.constructorClass().initialize(); - //else if (sym.isModule()) sym.moduleClass().initialize(); - defineSym(tree, u, 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) { - Type constrtype = tree.symbol().constructor().type().instanceType(); - switch (tree) { - case ClassDef(_, _, _, ValDef[][] vparams, _, _): - if (vparams.length == 0) { - constrtype = removeMethod(constrtype); - } - } - sym.setInfo(constrtype); - } - private Type removeMethod(Type tp) { - switch (tp) { - case MethodType(_, Type restp): - return restp; - case PolyType(Symbol[] tparams, Type restp): - return Type.PolyType(tparams, removeMethod(restp)); - default: - return tp; - } - } - } - - /** A lazy type for self types - */ - class LazySelfType extends LazyTreeType { - LazySelfType(Tree tree) { - super(tree); - } - public void complete(Symbol sym) { - defineSelfType(sym, tree, u, c); - } - } } diff --git a/sources/scalac/typechecker/Context.java b/sources/scalac/typechecker/Context.java index 5c01e9d73e..090f0e58fb 100644 --- a/sources/scalac/typechecker/Context.java +++ b/sources/scalac/typechecker/Context.java @@ -20,7 +20,6 @@ public class Context { Context enclClass = this; // The next outer context whose tree // is a class template int variance; // Variance relative to eclosing class. - boolean delayArgs = false; // delay checking of type arguments public Context() {} @@ -37,7 +36,6 @@ public class Context { tree instanceof Tree.CompoundType) this.enclClass = this; else this.enclClass = outer.enclClass; this.variance = outer.variance; - this.delayArgs = outer.delayArgs; this.outer = outer; } diff --git a/sources/scalac/typechecker/DeSugarize.java b/sources/scalac/typechecker/DeSugarize.java index e5f2b2095d..89f82cec0d 100644 --- a/sources/scalac/typechecker/DeSugarize.java +++ b/sources/scalac/typechecker/DeSugarize.java @@ -163,7 +163,7 @@ public class DeSugarize implements Kinds, Modifiers { } /** (x_1: T_1, ..., x_n: T_N) => e ==> - * new new scala.Object() with scala.Function[T_1, ..., T_N, T]() { + * new scala.Object() with scala.Function[T_1, ..., T_N, T]() { * def apply(x_1: T_1, ..., x_N: T_N): T = e * def toString(): java.lang.String = "<function>" * } @@ -232,7 +232,6 @@ public class DeSugarize implements Kinds, Modifiers { * Cases' = case P1 if G1 => True, ..., Pn if Gn => True, _ => False * Argtpe = targs[0] * Restpe = targs[1] - */ public Tree partialFunction(Tree tree, Type pattpe, Type restpe) { Tree constr = make.Apply( @@ -271,8 +270,9 @@ public class DeSugarize implements Kinds, Modifiers { print(tree, "partialfun", result); return result; } + */ - private Tree isDefinedAtVisitor(Tree tree) { + Tree isDefinedAtVisitor(Tree tree) { switch (tree) { case Visitor(CaseDef[] cases): CaseDef lastCase = cases[cases.length - 1]; @@ -310,7 +310,7 @@ public class DeSugarize implements Kinds, Modifiers { /** match => this.match * match[targs] => this.match[targs] - * tree is already attributed and attributes need to be preserved. + * IMPORTANT: tree is already attributed and attributes need to be preserved. */ Tree postMatch(Tree tree, Symbol currentclazz) { switch (tree) { @@ -507,7 +507,7 @@ public class DeSugarize implements Kinds, Modifiers { Name valname = Name.fromString(name + "$"); Tree valdef1 = copy.ValDef( tree, (mods & (DEFERRED | MUTABLE | CASEACCESSOR | MODUL)) | PRIVATE, - valname, tpe, rhs); + valname, tpe, rhs).setType(null); int mods1 = mods | ACCESSOR; if ((mods1 & MUTABLE) == 0) mods1 |= STABLE; Tree getter = make.DefDef( @@ -540,33 +540,6 @@ public class DeSugarize implements Kinds, Modifiers { } } - /** 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'. - */ - public Tree toConstructor(Tree tree, Symbol constr) { - switch (tree) { - case Apply(Tree fn, Tree[] args): - return toConstructor1(tree, constr); - default: - return make.Apply(tree.pos, toConstructor1(tree, constr), Tree.EMPTY_ARRAY); - } - } - private Tree toConstructor1(Tree tree, Symbol constr) { - switch (tree) { - case Apply(Tree fn, Tree[] args): - return copy.Apply(tree, toConstructor1(fn, constr), args); - case TypeApply(Tree fn, Tree[] args): - return copy.TypeApply(tree, toConstructor1(fn, constr), args); - case Ident(Name name): - return copy.Ident(tree, constr.name).setSymbol(constr); - case Select(Tree qual, Name name): - return copy.Select(tree, qual, constr.name).setSymbol(constr); - default: - throw new ApplicationError(); - } - } - /** Expand partial function applications of type `type'. * * p.f(es_1)...(es_n) @@ -601,13 +574,14 @@ public class DeSugarize implements Kinds, Modifiers { return tree; case Select(Tree qual, _): - return copy.Select(tree, liftout(qual, defs)); + return copy.Select(tree, liftout(qual, defs)).setType(null); case TypeApply(Tree fn, Tree[] args): - return copy.TypeApply(tree, liftoutPrefix(fn, defs), args); + return copy.TypeApply(tree, liftoutPrefix(fn, defs), args).setType(null); case Apply(Tree fn, Tree[] args): - return copy.Apply(tree, liftoutPrefix(fn, defs), liftout(args, defs)); + return copy.Apply(tree, liftoutPrefix(fn, defs), liftout(args, defs)) + .setType(null); default: throw new ApplicationError(); diff --git a/sources/scalac/typechecker/Infer.java b/sources/scalac/typechecker/Infer.java index a212e26e77..9852e2d1f1 100644 --- a/sources/scalac/typechecker/Infer.java +++ b/sources/scalac/typechecker/Infer.java @@ -241,9 +241,32 @@ public class Infer implements Modifiers, Kinds { */ private boolean isWithinBounds(Symbol[] tparams, Type[] targs) { for (int i = 0; i < targs.length; i++) { - if (!targs[i].isSubType(tparams[i].info().subst(tparams, targs)) || - !tparams[i].loBound().subst(tparams, targs).isSubType(targs[i])) + Type hibound = tparams[i].info().subst(tparams, targs); + if (!targs[i].isSubType(hibound)) { + for (int j = 0; j < tparams.length; j++) { + if (hibound.symbol() == tparams[j]) + return isWithinBounds( + tparams, + Type.subst( + targs, + new Symbol[]{tparams[j]}, + new Type[]{targs[i]})); + } return false; + } + Type lobound = tparams[i].loBound().subst(tparams, targs); + if (!lobound.isSubType(targs[i])) { + for (int j = 0; j < tparams.length; j++) { + if (lobound.symbol() == tparams[j]) + return isWithinBounds( + tparams, + Type.subst( + targs, + new Symbol[]{tparams[j]}, + new Type[]{targs[i]})); + } + return false; + } } return true; } @@ -444,7 +467,7 @@ public class Infer implements Modifiers, Kinds { private Symbol[] normalizeArgs(Type[] targs, Symbol[] tparams) { Type.List uninstantiated = Type.List.EMPTY; for (int i = 0; i < targs.length; i++) { - if (targs[i] == Global.instance.definitions.ALL_TYPE) { + if (targs[i].symbol() == Global.instance.definitions.ALL_CLASS) { targs[i] = tparams[i].type(); uninstantiated = Type.List.append(uninstantiated, targs[i]); } diff --git a/sources/scalac/typechecker/RefCheck.java b/sources/scalac/typechecker/RefCheck.java index c40341c1d0..3719fe0664 100644 --- a/sources/scalac/typechecker/RefCheck.java +++ b/sources/scalac/typechecker/RefCheck.java @@ -16,7 +16,22 @@ import scalac.ast.printer.*; import scalac.symtab.*; import Tree.*; -/** Check that no forward reference to a term symbol extends beyond a value definition. +/** Post-attribution checking and transformation. + * + * This phase performs the following checks. + * + * - All overrides conform to rules. + * - All type arguments conform to bounds. + * - All type variable uses conform to variance annotations. + * - No forward reference to a term symbol extends beyond a value definition. + * + * It preforms the following transformations. + * + * - Local modules are replaces by variables and classes + * - toString, equals, and hashCode methods are added to case classes, unless + * they are defined in the class or a baseclass different from java.lang.Object + * - Calls to case factory methods are replaced by new's. + * - Type nodes are replaced by TypeTerm nodes. */ public class RefCheck extends Transformer implements Modifiers, Kinds { @@ -25,15 +40,238 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { } private Unit unit; + private Definitions defs = global.definitions; + private Infer infer = new Infer(this); + + public void apply(Unit unit) { + this.unit = unit; + level = 0; + scopes[0] = new Scope(); + maxindex[0] = Integer.MIN_VALUE; + unit.body = transformStats(unit.body); + scopes[0] = null; + symIndex.clear(); + } + +// Override checking ------------------------------------------------------------ + + /** Check all members of class `clazz' for overriding conditions. + */ + void checkAllOverrides(int pos, 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 && (other.flags & PRIVATE) == 0 && + member.kind != NONE) + checkOverride(pos, clazz, member, other); + if ((member.flags & DEFERRED) != 0 && + clazz.kind == CLASS && + (clazz.flags & ABSTRACTCLASS) == 0) { + if (clazz.isAnonymousClass()) + unit.error( + clazz.pos, "object creation impossible, since " + + member + member.locationString() + " is not defined" + + (((member.flags & MUTABLE) == 0) ? "" + : "\n(Note that variables need to be initialized to be defined)")); + else + unit.error(clazz.pos, + clazz + " needs to be abstract; it does not define " + + member + member.locationString() + + (((member.flags & MUTABLE) == 0) ? "" + : "\n(Note that variables need to be initialized to be defined)")); + clazz.flags |= ABSTRACTCLASS; + } + } + } + } + + /** Check that all conditions for overriding `other' by `member' are met. + */ + void checkOverride(int pos, Symbol clazz, Symbol member, Symbol other) { + if (member.owner() == clazz) pos = member.pos; + else if (member.owner().isSubClass(other.owner())) + return; // everything was already checked elsewhere + + if ((member.flags & PRIVATE) != 0) { + 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)) { + overrideError(pos, member, other, "needs `override' modifier"); + } else if (other.isStable() && !member.isStable()) { + overrideError(pos, member, other, "needs to be an immutable value"); + } else { + Type self = clazz.thisType(); + switch (other.kind) { + case CLASS: + overrideError(pos, member, other, "cannot override a class"); + break; + case ALIAS: + 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"); + Type selftype = normalizedInfo(self, member); + Type othertype = normalizedInfo(self, other); + if (!selftype.isSubType(othertype)) + overrideTypeError(pos, member, other, self, false); + if (member.kind == TYPE && + !self.memberLoBound(other).isSubType( + self.memberLoBound(member))) + overrideTypeError(pos, member, other, self, true); + + } + } + } + + void overrideError(int pos, Symbol member, Symbol other, String msg) { + if (other.type() != Type.ErrorType && member.type() != Type.ErrorType) + unit.error(pos, + "error overriding " + other + other.locationString() + + ";\n " + member + member.locationString() + " " + msg); + } + + 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); + unit.error(pos, + member + member.locationString() + + infoString(member, memberInfo, lobound) + + "\n cannot override " + other + other.locationString() + + infoString(other, otherInfo, lobound)); + Type.explainTypes(memberInfo, otherInfo); + } + } + + Type normalizedInfo(Type site, Symbol sym) { + Type tp = site.memberInfo(sym); + if (sym.kind == VAL && (sym.flags & STABLE) != 0) tp = tp.resultType(); + return tp; + } + + String infoString(Symbol sym, Type symtype, boolean lobound) { + switch (sym.kind) { + case ALIAS: return ", which equals " + symtype; + case TYPE: return " bounded" + (lobound ? " from below" : "") + " by " + symtype; + case VAL: return " of type " + symtype; + default: return ""; + } + } + + /** compensate for renaming during addition of access functions + */ + Name normalize(Name name) { + return (name.endsWith(Name.fromString("$"))) + ? name.subName(0, name.length() - 1) + : name; + } + +// Variance Checking -------------------------------------------------------- + + private final int + ContraVariance = -1, + NoVariance = 0, + CoVariance = 1, + AnyVariance = 2; + + private String varianceString(int variance) { + if (variance == 1) return "covariant"; + else if (variance == -1) return "contravariant"; + else return "invariant"; + } + + /** The variance of symbol `base' relative to the class which defines `tvar'. + */ + int flip(Symbol base, Symbol tvar) { + Symbol clazz = tvar.owner().primaryConstructorClass(); + Symbol sym = base; + int flip = CoVariance; + while (sym != clazz && flip != AnyVariance) { + //System.out.println("flip: " + sym + " " + sym.isParameter());//DEBUG + if (sym.isParameter()) flip = -flip; + else if (sym.owner().kind != CLASS) flip = AnyVariance; + else if (sym.kind == ALIAS) flip = NoVariance; + sym = sym.owner(); + } + return flip; + } + + /** Check variance of type variables in this type + */ + void validateVariance(Symbol base, Type tp, int variance) { + validateVariance(base, tp, tp, variance); + } + + void validateVariance(Symbol base, Type all, Type tp, int variance) { + switch (tp) { + case ErrorType: + case AnyType: + case NoType: + case ThisType(Symbol sym): + break; + case SingleType(Type pre, Symbol sym): + validateVariance(base, all, pre, variance); + break; + case TypeRef(Type pre, Symbol sym, Type[] args): + if (sym.variance() != 0) { + int f = flip(base, sym); + if (f != AnyVariance && sym.variance() != f * variance) { + //System.out.println("flip(" + base + "," + sym + ") = " + f);//DEBUG + unit.error(base.pos, + varianceString(sym.variance()) + " " + sym + + " occurs in " + varianceString(f * variance) + + " position in type " + all + " of " + base); + } + } + validateVariance(base, all, pre, variance); + validateVariance(base, all, args, variance, sym.typeParams()); + break; + case CompoundType(Type[] parts, Scope members): + validateVariance(base, all, parts, variance); + break; + case MethodType(Symbol[] vparams, Type result): + validateVariance(base, all, result, variance); + break; + case PolyType(Symbol[] tparams, Type result): + validateVariance(base, all, result, variance); + break; + case OverloadedType(Symbol[] alts, Type[] alttypes): + validateVariance(base, all, alttypes, variance); + } + } + + void validateVariance(Symbol base, Type all, Type[] tps, int variance) { + for (int i = 0; i < tps.length; i++) + validateVariance(base, all, tps[i], variance); + } + + void validateVariance(Symbol base, Type all, Type[] tps, int variance, Symbol[] tparams) { + for (int i = 0; i < tps.length; i++) + validateVariance(base, all, tps[i], variance * tparams[i].variance()); + } + +// Forward reference checking --------------------------------------------------- + private Scope[] scopes = new Scope[4]; private int[] maxindex = new int[4]; private int[] refpos = new int[4]; private Symbol[] refsym = new Symbol[4]; private int level; private HashMap symIndex = new HashMap(); - private Definitions defs = global.definitions; - void pushLevel() { + private void pushLevel() { level++; if (level == scopes.length) { Scope[] scopes1 = new Scope[scopes.length * 2]; @@ -53,36 +291,18 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { maxindex[level] = Integer.MIN_VALUE; } - void popLevel() { + private void popLevel() { scopes[level] = null; level --; } - public void apply(Unit unit) { - this.unit = unit; - level = 0; - scopes[0] = new Scope(); - maxindex[0] = Integer.MIN_VALUE; - unit.body = transformStats(unit.body); - scopes[0] = null; - symIndex.clear(); - } - - /** compensate for renaming during addition of access functions - */ - Name normalize(Name name) { - return (name.endsWith(Name.fromString("$"))) - ? name.subName(0, name.length() - 1) - : name; - } - - void enterSyms(Tree[] stats) { + private void enterSyms(Tree[] stats) { for (int i = 0; i < stats.length; i++) { enterSym(stats[i], i); } } - void enterSym(Tree stat, int index) { + private void enterSym(Tree stat, int index) { Symbol sym = null; switch (stat) { case ClassDef(_, _, _, _, _, _): @@ -99,27 +319,7 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { } } - public Tree[] transformStats(Tree[] stats) { - pushLevel(); - enterSyms(stats); - int i = 0; - while (i < stats.length) { - Tree[] newstat = transformStat(stats[i], i); - if (newstat != null) { - Tree[] newstats = new Tree[stats.length + newstat.length - 1]; - System.arraycopy(stats, 0, newstats, 0, i); - System.arraycopy(newstat, 0, newstats, i, newstat.length); - System.arraycopy(stats, i + 1, newstats, i + newstat.length, - stats.length - i - 1); - i = i + newstat.length; - stats = newstats; - } else { - i = i + 1; - } - } - popLevel(); - return stats; - } +// Module eliminiation ----------------------------------------------------------- private Tree[] transformModule(Tree tree, int mods, Name name, Tree tpe, Tree.Template templ) { Symbol sym = tree.symbol(); @@ -181,6 +381,8 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { } } +// Adding case methods -------------------------------------------------------------- + private boolean hasImplementation(Symbol clazz, Name name) { Symbol sym = clazz.info().lookupNonPrivate(name); return sym.kind == VAL && @@ -275,68 +477,67 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { Type.MethodType(new Symbol[]{equalsParam}, defs.BOOLEAN_TYPE)); clazz.info().members().enter(equalsSym); Tree[] fields = caseFields(clazz); - 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] = defs.ANY_TYPE; - constrtype = restp.subst(tparams, targs); + Type testtp = clazz.type(); + { + Symbol[] tparams = clazz.typeParams(); + if (tparams.length != 0) { + Type[] targs = new Type[tparams.length]; + for (int i = 0; i < targs.length; i++) + targs[i] = defs.ANY_TYPE; + testtp = testtp.subst(tparams, targs); + } } - Tree[] patargs = patternVars(clazz.pos, constrtype, equalsSym); - Tree pattern = make.Apply( - clazz.pos, gen.mkType(clazz.pos, constrtype), patargs) - .setType(clazz.type()); - Tree rhs; + + // if (that is C) {... + Tree cond = gen.TypeApply( + gen.Select( + gen.mkRef(clazz.pos, Type.localThisType, equalsParam), + defs.IS), + new Tree[]{gen.mkType(clazz.pos, testtp)}); + + Tree thenpart; if (fields.length == 0) { - rhs = gen.mkBooleanLit(clazz.pos, true); + thenpart = gen.mkBooleanLit(clazz.pos, true); } else { - rhs = eqOp(fields[0], patargs[0]); + // val that1 = that as C; + Tree cast = gen.TypeApply( + gen.Select( + gen.mkRef(clazz.pos, Type.localThisType, equalsParam), + defs.AS), + new Tree[]{gen.mkType(clazz.pos, testtp)}); + Symbol that1sym = new TermSymbol(clazz.pos, Names.that1, equalsSym, 0) + .setType(testtp); + Tree that1def = gen.ValDef(that1sym, cast); + + // this.elem_1 == that1.elem_1 && ... && this.elem_n == that1.elem_n + Tree cmp = eqOp( + fields[0], + qualCaseField(clazz, + gen.mkRef(clazz.pos, Type.localThisType, that1sym), 0)); for (int i = 1; i < fields.length; i++) { - rhs = gen.Apply( - gen.Select(rhs, defs.AMPAMP()), - new Tree[]{eqOp(fields[i], patargs[i])}); + cmp = gen.Apply( + gen.Select(cmp, defs.AMPAMP()), + new Tree[]{ + eqOp( + fields[i], + qualCaseField(clazz, + gen.mkRef(clazz.pos, Type.localThisType, that1sym), i))}); } + thenpart = gen.Block(new Tree[]{that1def, cmp}); } - CaseDef case1 = (Tree.CaseDef) make.CaseDef( - clazz.pos, pattern, Tree.Empty, rhs) - .setType(defs.BOOLEAN_TYPE); - CaseDef case2 = (Tree.CaseDef) make.CaseDef(clazz.pos, - patternVar(clazz.pos, Names.WILDCARD, defs.ANY_TYPE, equalsSym), - Tree.Empty, - gen.mkBooleanLit(clazz.pos, false)) - .setType(defs.BOOLEAN_TYPE); - Tree body = make.Apply(clazz.pos, - gen.Select( - gen.mkRef(clazz.pos, Type.localThisType, equalsParam), - defs.MATCH), - new Tree[]{make.Visitor(clazz.pos, new CaseDef[]{case1, case2}) - .setType(defs.BOOLEAN_TYPE)}) - .setType(defs.BOOLEAN_TYPE); - return gen.DefDef(clazz.pos, equalsSym, body); + Tree body = gen.If(cond, thenpart, gen.mkBooleanLit(clazz.pos, false)); + return gen.DefDef(equalsSym, body); } //where - private Tree patternVar(int pos, Name name, Type tp, Symbol owner) { - return make.Ident(pos, name) - .setSymbol(new TermSymbol(pos, name, owner, 0).setType(tp)) - .setType(tp); - } - - private Tree[] patternVars(int pos, Type constrtype, Symbol owner) { - Symbol[] vparams = constrtype.firstParams(); - Tree[] pats = new Tree[vparams.length]; - for (int i = 0; i < pats.length; i++) { - pats[i] = patternVar( - pos, vparams[i].name, vparams[i].type(), owner); - } - return pats; - } - private Tree eqOp(Tree l, Tree r) { Symbol eqMethod = getUnaryMemberMethod(l.type, Names.EQEQ, r.type); return gen.Apply(gen.Select(l, eqMethod), new Tree[]{r}); } + private Tree qualCaseField(ClassSymbol clazz, Tree qual, int i) { + return gen.Select(qual, clazz.caseFieldAccessor(i)); + } + private Tree hashCodeMethod(ClassSymbol clazz) { Symbol hashCodeSym = new TermSymbol( clazz.pos, Names.hashCode, clazz, OVERRIDE) @@ -401,33 +602,22 @@ 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; +// Convert case factory calls to constructor calls --------------------------- + + /** 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); } } //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): @@ -463,17 +653,64 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { } } - /** The main checking functions - */ - public Tree[] transformStat(Tree tree, int index) { - Tree resultTree; +// Bounds checking ----------------------------------------------------------- + + private void checkBounds(int pos, Symbol[] tparams, Type[] argtypes) { + if (tparams.length == argtypes.length) { + try { + infer.checkBounds(tparams, argtypes, ""); + } catch (Type.Error ex) { + unit.error(pos, ex.msg); + } + } + } + +// Type node eliminiation ------------------------------------------------------ + + private Tree elimTypeNode(Tree tree) { + if (tree.isType() && !tree.isMissing()) + return make.TypeTerm(tree.pos).setType(tree.type); + else + return tree; + } + +// Transformation --------------------------------------------------------------- + + public Tree[] transformStats(Tree[] stats) { + pushLevel(); + enterSyms(stats); + int i = 0; + while (i < stats.length) { + Object stat1 = transformStat(stats[i], i); + if (stat1 instanceof Tree) { + stats[i] = (Tree) stat1; + i = i + 1; + } else { + Tree[] newstats = (Tree[]) stat1; + Tree[] stats1 = new Tree[stats.length - 1 + newstats.length]; + System.arraycopy(stats, 0, stats1, 0, i); + System.arraycopy(newstats, 0, stats1, i, newstats.length); + System.arraycopy(stats, i + 1, stats1, i + newstats.length, + stats.length - i - 1); + stats = stats1; + i = i + newstats.length; + } + } + popLevel(); + return stats; + } + + public Object transformStat(Tree tree, int index) { switch (tree) { case ModuleDef(int mods, Name name, Tree tpe, Tree.Template templ): return transform(transformModule(tree, mods, name, tpe, templ)); case ValDef(int mods, Name name, Tree tpe, Tree rhs): Symbol sym = tree.symbol(); - resultTree = transform(tree); + validateVariance( + sym, sym.type(), + ((sym.flags & MUTABLE) != 0) ? NoVariance : CoVariance); + Tree tree1 = transform(tree); //todo: handle variables if (sym.isLocal() && !sym.isModule() && index <= maxindex[level]) { if (Global.instance.debug) @@ -483,36 +720,86 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { "forward reference extends over definition of value " + normalize(name)); } - break; + return tree1; default: - resultTree = transform(tree); + return transform(tree); } - return (resultTree == tree) ? null : new Tree[]{resultTree}; } public Tree transform(Tree tree) { - Tree tree1; + Symbol sym = tree.symbol(); switch (tree) { case ClassDef(_, _, Tree.TypeDef[] tparams, Tree.ValDef[][] vparams, Tree tpe, Tree.Template templ): + validateVariance(sym, sym.info(), CoVariance); + validateVariance(sym, sym.typeOfThis(), CoVariance); return super.transform( copy.ClassDef(tree, tree.symbol(), tparams, vparams, tpe, addCaseMethods(templ, tree.symbol()))); + case DefDef(_, _, _, _, _, _): + validateVariance(sym, sym.type(), CoVariance); + return super.transform(tree); + + case TypeDef(_, _, _, _): + if (sym.kind == ALIAS) { + validateVariance(sym, sym.info(), NoVariance); + } else { + validateVariance(sym, sym.info(), CoVariance); + validateVariance(sym, sym.loBound(), ContraVariance); + } + return super.transform(tree); + case Template(Tree[] bases, Tree[] body): Tree[] bases1 = transform(bases); Tree[] body1 = transformStats(body); + if (sym.kind == VAL) { + checkAllOverrides(tree.pos, tree.symbol().owner()); + } return copy.Template(tree, bases1, body1); + case Block(Tree[] stats): Tree[] stats1 = transformStats(stats); return copy.Block(tree, stats1); + case This(_): return tree; + case PackageDef(Tree pkg, Template packaged): return copy.PackageDef(tree, pkg, super.transform(packaged)); + + case TypeApply(Tree fn, Tree[] args): + switch (fn.type) { + case PolyType(Symbol[] tparams, Type restp): + checkBounds(tree.pos, tparams, Tree.typeOf(args)); + } + return super.transform(tree); + + case Apply(Tree fn, Tree[] args): + Symbol fsym = TreeInfo.methSymbol(fn); + 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(); + tree = gen.New(toConstructor(tree, constr)); + } + return super.transform(tree); + + case AppliedType(Tree tpe, Tree[] args): + //todo: this needs to be refined. + Symbol[] tparams = + (Type.isSameAs( + tpe.type.typeArgs(), Symbol.type(tpe.type.typeParams()))) + ? tpe.type.typeParams() : Symbol.EMPTY_ARRAY; + checkBounds(tree.pos, tparams, Tree.typeOf(args)); + return elimTypeNode(super.transform(tree)); + + case CompoundType(_, _): + checkAllOverrides(tree.pos, tree.type.symbol()); + return elimTypeNode(super.transform(tree)); + case Ident(Name name): Scope.Entry e = scopes[level].lookupEntry(name); - Symbol sym = tree.symbol(); - assert sym != null : name; if (sym.isLocal() && sym == e.sym) { int i = level; while (scopes[i] != e.owner) i--; @@ -523,14 +810,12 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { maxindex[i] = symindex; } } - tree1 = convertCaseFactoryCall(tree); - break; + return elimTypeNode(tree); + default: - tree1 = super.transform(convertCaseFactoryCall(tree)); + return elimTypeNode(super.transform(tree)); } - if (tree1.isType() && !tree1.isMissing()) - tree1 = gen.mkType(tree1.pos, tree1.type); - return tree1; - } + + } } diff --git a/sources/scalac/util/Names.java b/sources/scalac/util/Names.java index b7e2b0e0c2..f2cfab763d 100644 --- a/sources/scalac/util/Names.java +++ b/sources/scalac/util/Names.java @@ -82,7 +82,6 @@ public class Names { public static final Name runtime = Name.fromString("runtime"); public static final Name scala = Name.fromString("scala"); public static final Name scala_COLONCOLON = Name.fromString("scala." + COLONCOLON); - public static final Name scala_Algebraic = Name.fromString("scala.Algebraic"); public static final Name scala_All = Name.fromString("scala.All"); public static final Name scala_AllRef = Name.fromString("scala.AllRef"); public static final Name scala_Any = Name.fromString("scala.Any"); @@ -113,6 +112,7 @@ public class Names { 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 that1 = Name.fromString("that1"); public static final Name this_ = Name.fromString("this"); public static final Name throw_ = Name.fromString("throw"); public static final Name true_ = Name.fromString("true"); diff --git a/test/files/neg/bounds.check b/test/files/neg/bounds.check index 0f4693da88..461086194f 100644 --- a/test/files/neg/bounds.check +++ b/test/files/neg/bounds.check @@ -1,4 +1,4 @@ -bounds.scala:11: constructor A of type [T >: I](T)A[T] cannot be applied to [T] +bounds.scala:11: type arguments [T] do not conform to constructor A's type parameter bounds [T >: I] class B[T >: J](init: T) extends A[T](init) { ^ one error found diff --git a/test/files/pos/partialfun.scala b/test/files/pos/partialfun.scala index e6af633811..21e4d0a096 100644 --- a/test/files/pos/partialfun.scala +++ b/test/files/pos/partialfun.scala @@ -4,7 +4,7 @@ object partialfun { if (f.isDefinedAt(x)) f(x) else "<undefined>"; applyPartial { - case Some(x) => x + case Some(xxx) => xxx } (None); }
\ No newline at end of file diff --git a/test/files/run/Course-2002-02.scala b/test/files/run/Course-2002-02.scala index 6c78249586..fc9add8371 100644 --- a/test/files/run/Course-2002-02.scala +++ b/test/files/run/Course-2002-02.scala @@ -79,7 +79,7 @@ object M3 { if (a > b) 0 else f(a) + sum(f, a + 1, b); - def sumInts(a: Int, b: Int): Double = sum((x => x), a, b); + def sumInts(a: Int, b: Int): Double = sum((xXXXXX => xXXXXX), a, b); def sumCubes(a: Int, b: Int): Double = sum((x => x * x * x), a, b); def sumReciprocals(a: Int, b: Int): Double = sum((x => 1.0/x), a, b); def sumPi(n: Int): Double = 4 + sum((x => 4.0/(4*x+1) - 4.0/(4*x-1)), 1, n); diff --git a/test/neg/bounds.check b/test/neg/bounds.check index 0f4693da88..461086194f 100644 --- a/test/neg/bounds.check +++ b/test/neg/bounds.check @@ -1,4 +1,4 @@ -bounds.scala:11: constructor A of type [T >: I](T)A[T] cannot be applied to [T] +bounds.scala:11: type arguments [T] do not conform to constructor A's type parameter bounds [T >: I] class B[T >: J](init: T) extends A[T](init) { ^ one error found diff --git a/test/pos/partialfun.scala b/test/pos/partialfun.scala index e6af633811..21e4d0a096 100644 --- a/test/pos/partialfun.scala +++ b/test/pos/partialfun.scala @@ -4,7 +4,7 @@ object partialfun { if (f.isDefinedAt(x)) f(x) else "<undefined>"; applyPartial { - case Some(x) => x + case Some(xxx) => xxx } (None); }
\ No newline at end of file |