diff options
author | Martin Odersky <odersky@gmail.com> | 2003-04-30 09:06:27 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2003-04-30 09:06:27 +0000 |
commit | 21f24de326d79515c44f80665f9679410389b1ab (patch) | |
tree | bc8820c917f88ecda8469c90bd7f7298fdc27975 | |
parent | e0d3451834b3cc5748dadb6b53971c05878faee4 (diff) | |
download | scala-21f24de326d79515c44f80665f9679410389b1ab.tar.gz scala-21f24de326d79515c44f80665f9679410389b1ab.tar.bz2 scala-21f24de326d79515c44f80665f9679410389b1ab.zip |
*** empty log message ***
37 files changed, 567 insertions, 123 deletions
diff --git a/sources/meta/scalac/ast/Tree.java b/sources/meta/scalac/ast/Tree.java index a7a933069b..6fb25bf0b1 100644 --- a/sources/meta/scalac/ast/Tree.java +++ b/sources/meta/scalac/ast/Tree.java @@ -176,7 +176,8 @@ public class Tree { setRange(Phase.PARSER, Phase.ERASURE). // !!! could/should be removed earlier?) addField(t_int, "mods", SymFlags). addField(t_TypeName, "name", SymName). - addField(t_TypeTree, "rhs"); + addField(t_TypeTree, "rhs"). + addField(t_TypeTree, "lobound"); n_Import. setDescription("Import declaration"). diff --git a/sources/scala/Except.scala b/sources/scala/Except.scala index 123fe4dc07..ce73a35e9c 100644 --- a/sources/scala/Except.scala +++ b/sources/scala/Except.scala @@ -1,8 +1,8 @@ package scala; class Except[a](r: scala.runtime.ResultOrException[a]) { - def except(handler: PartialFunction[Throwable, a]): a = - if (r.exc == null) r.result as a + def except[b >: a](handler: PartialFunction[Throwable, b]): b = + if (r.exc == null) r.result as b else if (handler isDefinedAt r.exc) handler(r.exc) else r.exc.throw; def finally(def handler: Unit): a = diff --git a/sources/scala/Predef.scala b/sources/scala/Predef.scala index 61d6397c59..6ead2be1c1 100644 --- a/sources/scala/Predef.scala +++ b/sources/scala/Predef.scala @@ -15,12 +15,7 @@ object Predef { def List[a](x: a*): List[a] = x as List[a]; val List = scala.List; - def error[err](x: String):err = new java.lang.RuntimeException(x).throw; - - def abs(x: int): int = if (x < 0) -x else x; - def abs(x: long): long = if (x < 0) -x else x; - def abs(x: float): float = if (x < 0) -x else x; - def abs(x: double): double = if (x < 0) -x else x; + def error(x: String): All = new java.lang.RuntimeException(x).throw; def try[a](def block: a): Except[a] = new Except(scala.runtime.ResultOrException.tryBlock(block)); diff --git a/sources/scala/Stream.scala b/sources/scala/Stream.scala index 984f3f362e..461725e53e 100644 --- a/sources/scala/Stream.scala +++ b/sources/scala/Stream.scala @@ -6,8 +6,6 @@ trait Stream[a] { def head: a; def tail: Stream[a]; - protected def error[a](x: String):a = (new java.lang.RuntimeException(x)).throw; - def length: Int = if (isEmpty) 0 else tail.length + 1; def append(def rest: Stream[a]): Stream[a] = diff --git a/sources/scalac/Global.java b/sources/scalac/Global.java index 0df78993cb..606fb4f639 100644 --- a/sources/scalac/Global.java +++ b/sources/scalac/Global.java @@ -397,7 +397,7 @@ public class Global { case PackageDef(_, _): case ModuleDef(_, _, _, _): case DefDef(_, _, _, _, _, _): - case TypeDef(_, _,_ ): + case TypeDef(_, _, _, _): if (!mustShow(tree.symbol())) return; body.append( treeGen.Apply( diff --git a/sources/scalac/ast/TreeGen.java b/sources/scalac/ast/TreeGen.java index 864609e7f8..47df5ae26c 100644 --- a/sources/scalac/ast/TreeGen.java +++ b/sources/scalac/ast/TreeGen.java @@ -252,7 +252,8 @@ public class TreeGen implements Kinds, Modifiers { pos, sym.flags & SOURCEFLAGS, sym.name, - TypeTerm(pos, symtype)) + TypeTerm(pos, symtype), + TypeTerm(pos, sym.loBound())) .setSymbol(sym).setType(definitions.UNIT_TYPE); } diff --git a/sources/scalac/ast/TreeInfo.java b/sources/scalac/ast/TreeInfo.java index 17ca034316..f377468e08 100644 --- a/sources/scalac/ast/TreeInfo.java +++ b/sources/scalac/ast/TreeInfo.java @@ -44,7 +44,7 @@ public class TreeInfo { case ModuleDef(_, _, _, _): case DefDef(_, _, _, _, _, _): case ValDef(_, _, _, _): - case TypeDef(_, _, _): + case TypeDef(_, _, _, _): case Import(_, _): return true; default: @@ -58,7 +58,7 @@ public class TreeInfo { return rhs == Tree.Empty; case ValDef(_, _, _, Tree rhs): return rhs == Tree.Empty; - case TypeDef(_, _, _): + case TypeDef(_, _, _, _): return true; default: return false; @@ -72,7 +72,7 @@ public class TreeInfo { case ClassDef(_, _, _, _, _, _): case ModuleDef(_, _, _, _): case DefDef(_, _, _, _, _, _): - case TypeDef(_, _, _): + case TypeDef(_, _, _, _): case Import(_, _): return true; case ValDef(int mods, _, _, Tree rhs): diff --git a/sources/scalac/ast/parser/Parser.java b/sources/scalac/ast/parser/Parser.java index 1f086f93ba..589d33c31c 100644 --- a/sources/scalac/ast/parser/Parser.java +++ b/sources/scalac/ast/parser/Parser.java @@ -15,8 +15,6 @@ import scalac.symtab.Modifiers; import scalac.ast.*; import Tree.*; -//todo: add type idents? - /** A recursive descent parser for the programming language Scala. * * @author Martin Odersky, Matthias Zenger @@ -1198,26 +1196,29 @@ public class Parser implements Tokens { return (ValDef)make.ValDef(pos, mods, name, tp, Tree.Empty); } - /** TypeParamClauseOpt ::= [`[' TypeSig {`,' TypeSig} `]'] + /** TypeParamClauseOpt ::= [`[' TypeParam {`,' TypeParam} `]'] + * FunTypeParamClauseOpt ::= [`[' FunTypeParam {`,' FunTypeParam} `]'] */ - TypeDef[] typeParamClauseOpt() { + TypeDef[] typeParamClauseOpt(boolean variant) { TreeList params = new TreeList(); if (s.token == LBRACKET) { s.nextToken(); - params.append(typeSig(Modifiers.PARAM)); + params.append(typeParam(variant)); while (s.token == COMMA) { s.nextToken(); - params.append(typeSig(Modifiers.PARAM)); + params.append(typeParam(variant)); } accept(RBRACKET); } return (TypeDef[])params.copyTo(new TypeDef[params.length()]); } - /** TypeSig ::= [+ | -] Id TypeBounds + /** TypeParam ::= [`+' | `-'] FunTypeParam + * FunTypeParam ::= Id TypeBounds */ - Tree typeSig(int mods) { - if (s.token == IDENTIFIER) { + Tree typeParam(boolean variant) { + int mods = Modifiers.PARAM; + if (variant && s.token == IDENTIFIER) { if (s.name == PLUS) { s.nextToken(); mods |= Modifiers.COVARIANT; @@ -1229,7 +1230,7 @@ public class Parser implements Tokens { return typeBounds(s.pos, mods, ident()); } - /** TypeBounds ::= [>: Type] [<: Type] + /** TypeBounds ::= [`>:' Type] [`<:' Type] */ Tree typeBounds(int pos, int mods, Name name) { Tree lobound; @@ -1246,7 +1247,7 @@ public class Parser implements Tokens { } else { hibound = scalaDot(pos, Names.Any.toTypeName()); } - return make.TypeDef(pos, mods, name.toTypeName(), hibound); + return make.TypeDef(pos, mods, name.toTypeName(), hibound, lobound); } //////// DEFS //////////////////////////////////////////////////////////////// @@ -1351,7 +1352,7 @@ public class Parser implements Tokens { * | var ValSig {`,' ValSig} * | def FunSig {`,' FunSig} * | constr ConstrSig {`,' ConstrSig} - * | type TypeSig {`,' TypeSig} + * | type TypeDcl {`,' TypeDcl} */ Tree[] defOrDcl(int mods) { TreeList ts = new TreeList(); @@ -1470,13 +1471,13 @@ public class Parser implements Tokens { } } - /** FunDef ::= Id [TypeParamClause] {ParamClause} [`:' Type] `=' Expr - * FunSig ::= Id [TypeParamClause] {ParamClause} `:' Type + /** FunDef ::= Id [FunTypeParamClause] {ParamClause} [`:' Type] `=' Expr + * FunSig ::= Id [FunTypeParamClause] {ParamClause} `:' Type */ Tree funDefOrSig(int mods) { int pos = s.pos; Name name = ident(); - TypeDef[] tparams = typeParamClauseOpt(); + TypeDef[] tparams = typeParamClauseOpt(false); ValDef[][] vparams = paramClauses(); Tree restype = typedOpt(); if (s.token == EQUALS || restype == Tree.Empty) @@ -1487,12 +1488,12 @@ public class Parser implements Tokens { tparams, vparams, restype, Tree.Empty); } - /* ConstrDef ::= Id [TypeParamClause] [ParamClause] [`:' Type] `=' (Constr | BlockConstr) + /* ConstrDef ::= Id [FunTypeParamClause] [ParamClause] [`:' Type] `=' (Constr | BlockConstr) */ Tree constrDefOrSig(int mods) { int pos = s.pos; Name name = ident().toConstrName(); - TypeDef[] tparams = typeParamClauseOpt(); + TypeDef[] tparams = typeParamClauseOpt(false); ValDef[][] vparams = new ValDef[][]{paramClause()}; Tree restype = typedOpt(); if (s.token == EQUALS || restype == Tree.Empty) { @@ -1505,24 +1506,23 @@ public class Parser implements Tokens { } /** TypeDef ::= Id `=' Type - * TypeSig ::= [`+' | `-'] Id [`>:' Type] [`<:' Type] + * TypeDcl ::= Id TypeBounds */ Tree typeDefOrSig(int mods) { int pos = s.pos; - if (s.token == IDENTIFIER && (s.name == PLUS || s.name == MINUS)) - return typeSig(mods | Modifiers.DEFERRED); Name name = ident().toTypeName(); - if (s.token == SUPERTYPE || s.token == SUBTYPE) { - return typeBounds(pos, mods | Modifiers.DEFERRED, name); - } else if (s.token == EQUALS) { + switch (s.token) { + case EQUALS: s.nextToken(); - return make.TypeDef(pos, mods, name, type()); - } else if (s.token == SEMI || s.token == COMMA || s.token == RBRACE) { - return make.TypeDef( - pos, mods | Modifiers.DEFERRED, name, - scalaDot(pos, Names.Any.toTypeName())); - } else { - return syntaxError("`=', `>:', or `<:' expected", true); + return make.TypeDef(pos, mods, name, type(), Tree.Empty); + case SUPERTYPE: + case SUBTYPE: + case SEMI: + case COMMA: + case RBRACE: + return typeBounds(pos, mods | Modifiers.DEFERRED, name); + default: + return syntaxError("`=', `>:', or `<:' expected", true); } } @@ -1531,7 +1531,7 @@ public class Parser implements Tokens { Tree classDef(int mods) { int pos = s.pos; Name name = ident(); - TypeDef[] tparams = typeParamClauseOpt(); + TypeDef[] tparams = typeParamClauseOpt(true); ValDef[][] params = (s.token == LPAREN) ? new ValDef[][]{paramClause()} : Tree.ValDef_EMPTY_ARRAY_ARRAY; return make.ClassDef(pos, mods, name.toTypeName(), tparams, params, diff --git a/sources/scalac/ast/printer/TextTreePrinter.java b/sources/scalac/ast/printer/TextTreePrinter.java index c7375c1fcc..a943ca20f4 100644 --- a/sources/scalac/ast/printer/TextTreePrinter.java +++ b/sources/scalac/ast/printer/TextTreePrinter.java @@ -182,6 +182,7 @@ public class TextTreePrinter implements TreePrinter { protected static final Text TXT_DOT = Text.Simple("."); protected static final Text TXT_COMMA = Text.Simple(","); protected static final Text TXT_EQUAL = Text.Simple("="); + protected static final Text TXT_SUPERTYPE = Text.Simple(">:"); protected static final Text TXT_SUBTYPE = Text.Simple("<:"); protected static final Text TXT_HASH = Text.Simple("#"); protected static final Text TXT_RIGHT_ARROW = Text.Simple("=>"); @@ -317,13 +318,17 @@ public class TextTreePrinter implements TreePrinter { case TypeDef(int mods, Name name, - Tree rhs): + Tree rhs, + Tree lobound): printModifiers(mods); print(KW_TYPE); print(Text.Space); printSymbolDefinition(tree.symbol(), name); - if ((mods & (Modifiers.DEFERRED | Modifiers.PARAM)) != 0) printOpt(TXT_SUBTYPE, rhs, true); - else printOpt(TXT_EQUAL, rhs, true); + if ((mods & (Modifiers.DEFERRED | Modifiers.PARAM)) != 0) { + printBounds(lobound, rhs); + } else { + printOpt(TXT_EQUAL, rhs, true); + } break; case Import(Tree expr, Name[] selectors): @@ -683,10 +688,10 @@ public class TextTreePrinter implements TreePrinter { protected void printParam(Tree tree) { switch (tree) { - case TypeDef(int mods, Name name, Tree bound): + case TypeDef(int mods, Name name, Tree bound, Tree lobound): printModifiers(mods); printSymbolDefinition(tree.symbol(), name); - printOpt(TXT_SUBTYPE, bound, true); + printBounds(lobound, bound); break; case ValDef(int mods, Name name, Tree tpe, Tree.Empty): @@ -699,4 +704,12 @@ public class TextTreePrinter implements TreePrinter { Debug.abort("bad parameter: " + tree); } } + + protected void printBounds(Tree lobound, Tree hibound) { + if (lobound.toString() != "scala.All") + printOpt(TXT_SUPERTYPE, lobound, true); + if (hibound.toString() != "scala.Any") + printOpt(TXT_SUBTYPE, hibound, true); + } + } diff --git a/sources/scalac/backend/jvm/GenJVM.java b/sources/scalac/backend/jvm/GenJVM.java index 2bd62a05ea..c4b4909e75 100644 --- a/sources/scalac/backend/jvm/GenJVM.java +++ b/sources/scalac/backend/jvm/GenJVM.java @@ -458,7 +458,7 @@ class GenJVM { break; case Empty: - case TypeDef(_, _, _): + case TypeDef(_, _, _, _): case TypeApply(_, _): case FunType(_, _): case CompoundType(_, _): diff --git a/sources/scalac/checkers/CheckOwners.java b/sources/scalac/checkers/CheckOwners.java index 8c2bd926d2..6ee1187270 100644 --- a/sources/scalac/checkers/CheckOwners.java +++ b/sources/scalac/checkers/CheckOwners.java @@ -67,7 +67,7 @@ public class CheckOwners extends Checker { case ModuleDef(_,_,_,_): case DefDef(_,_,_,_,_,_): case ValDef(_,_,_,_): - case TypeDef(_,_,_): + case TypeDef(_,_,_, _): traverse(body[i], owner); break; default: @@ -134,9 +134,10 @@ public class CheckOwners extends Checker { traverse(rhs, tree.symbol()); } break; - case TypeDef(int mods, Name name, Tree rhs): { + case TypeDef(int mods, Name name, Tree rhs, Tree lobound): { check(tree); traverse(rhs, tree.symbol()); + // todo: we should do something about lobound here. } break; default: @@ -151,7 +152,7 @@ public class CheckOwners extends Checker { case ModuleDef(_,_,_,_): case DefDef(_,_,_,_,_,_): case ValDef(_,_,_,_): - case TypeDef(_,_,_): { + case TypeDef(_,_,_,_): { Symbol sym = tree.symbol(); if (sym != null && sym != Symbol.NONE) { checkOwner(tree, sym); diff --git a/sources/scalac/symtab/Definitions.java b/sources/scalac/symtab/Definitions.java index 93ab003055..5f2bf4735c 100644 --- a/sources/scalac/symtab/Definitions.java +++ b/sources/scalac/symtab/Definitions.java @@ -92,6 +92,16 @@ public class Definitions { public final Symbol OBJECT_CLASS; public final Type OBJECT_TYPE; + /** the scala.All class + */ + public final Symbol ALL_CLASS; + public final Type ALL_TYPE; + + /** the scala.AllRef class + */ + public final Symbol ALLREF_CLASS; + public final Type ALLREF_TYPE; + /** the primitive types */ public final Symbol BYTE_CLASS; @@ -220,6 +230,22 @@ public class Definitions { ANYVAL_CLASS = getClass(Names.scala_AnyVal); ANYVAL_TYPE = ANYVAL_CLASS.typeConstructor(); + // the scala.ALL class + ALL_CLASS = new ClassSymbol( + Position.NOPOS, Names.All.toTypeName(), SCALA_CLASS, 0); + SCALA_CLASS.members().enter(ALL_CLASS); + ALL_TYPE = ALL_CLASS.typeConstructor(); + ALL_CLASS.setInfo(Type.compoundType(new Type[]{ANY_TYPE}, new Scope(), ALL_CLASS)); + ALL_CLASS.constructor().setInfo(Type.MethodType(Symbol.EMPTY_ARRAY, ALL_TYPE)); + + // the scala.ALLREF class + ALLREF_CLASS = new ClassSymbol( + Position.NOPOS, Names.AllRef.toTypeName(), SCALA_CLASS, 0); + SCALA_CLASS.members().enter(ALLREF_CLASS); + ALLREF_TYPE = ALLREF_CLASS.typeConstructor(); + ALLREF_CLASS.setInfo(Type.compoundType(new Type[]{ANYREF_TYPE}, new Scope(), ALLREF_CLASS)); + ALLREF_CLASS.constructor().setInfo(Type.MethodType(Symbol.EMPTY_ARRAY, ALLREF_TYPE)); + // the primitive types DOUBLE_CLASS = getClass(Names.scala_Double); DOUBLE_TYPE = DOUBLE_CLASS.typeConstructor(); @@ -248,8 +274,7 @@ public class Definitions { JAVA_THROWABLE_TYPE = JAVA_THROWABLE_CLASS.typeConstructor(); THROW = new TermSymbol( Position.NOPOS, Names.throw_, JAVA_THROWABLE_CLASS, Modifiers.FINAL); - Symbol tvar = newTypeParameter(THROW, ANY_TYPE); - THROW.setInfo(Type.PolyType(new Symbol[]{tvar}, tvar.type())); + THROW.setInfo(ALL_TYPE); JAVA_THROWABLE_CLASS.members().enter(THROW); // add the java.lang.String class to the scala package @@ -292,7 +317,7 @@ public class Definitions { AS = new TermSymbol( Position.NOPOS, Names.as, ANY_CLASS, Modifiers.FINAL); - tvar = newTypeParameter(AS, ANY_TYPE); + Symbol tvar = newTypeParameter(AS, ANY_TYPE); AS.setInfo(Type.PolyType(new Symbol[]{tvar}, tvar.type())); ANY_CLASS.members().enter(AS); @@ -327,8 +352,7 @@ public class Definitions { // add a null value to the root scope NULL = new TermSymbol( Position.NOPOS, Names.null_, ROOT_CLASS, 0); - tvar = newTypeParameter(NULL, ANYREF_TYPE); - NULL.setInfo(Type.PolyType(new Symbol[]{tvar}, tvar.type())); + NULL.setInfo(ALLREF_TYPE); ROOT.members().enter(NULL); } @@ -338,8 +362,8 @@ public class Definitions { } private Symbol newTypeParameter(Symbol owner, Type bound) { - return new TypeSymbol( - Kinds.TYPE, Position.NOPOS, Name.fromString("T").toTypeName(), owner, Modifiers.PARAM) + return new AbsTypeSymbol( + Position.NOPOS, Name.fromString("T").toTypeName(), owner, Modifiers.PARAM) .setInfo(bound); } diff --git a/sources/scalac/symtab/Symbol.java b/sources/scalac/symtab/Symbol.java index f2e387c67b..eeb4d6e647 100644 --- a/sources/scalac/symtab/Symbol.java +++ b/sources/scalac/symtab/Symbol.java @@ -141,6 +141,12 @@ public abstract class Symbol implements Modifiers, Kinds { return this; } + /** Set the low bound of this type variable + */ + public Symbol setLoBound(Type lobound) { + throw new ApplicationError("setLoBound inapplicable for " + this); + } + // Symbol classification ---------------------------------------------------- /** Does this symbol denote a type? */ @@ -341,6 +347,14 @@ public abstract class Symbol implements Modifiers, Kinds { } } + /** The variance of this symbol as an integer + */ + public int variance() { + if ((flags & COVARIANT) != 0) return 1; + else if ((flags & CONTRAVARIANT) != 0) return -1; + else return 0; + } + // Symbol names ---------------------------------------------------------------- /** Get the fully qualified name of this Symbol @@ -592,6 +606,12 @@ public abstract class Symbol implements Modifiers, Kinds { throw new ApplicationError("typeConstructor inapplicable for " + this); } + /** The low bound of this type variable + */ + public Type loBound() { + throw new ApplicationError("loBound inapplicable for " + this); + } + /** Get this.type corresponding to this symbol */ public Type thisType() { @@ -1107,6 +1127,7 @@ public class TypeSymbol extends Symbol { private void computeClosure() { assert closures.closure != BAD_CLOSURE : this; closures.closure = BAD_CLOSURE; // to catch cycles. + // todo: why can't we do: inclClosure(SymSet.EMPTY, this) ? SymSet closureClassSet = inclClosureBases(SymSet.EMPTY, this); Symbol[] closureClasses = new Symbol[closureClassSet.size() + 1]; closureClasses[0] = this; @@ -1116,6 +1137,7 @@ public class TypeSymbol extends Symbol { //System.out.println(ArrayApply.toString(closures.closure));//DEBUG adjustType(type()); //System.out.println("closure(" + this + ") at " + Global.instance.currentPhase.name() + " = " + ArrayApply.toString(closures.closure));//DEBUG + } //where @@ -1151,6 +1173,36 @@ public class TypeSymbol extends Symbol { } } +public class AbsTypeSymbol extends TypeSymbol { + + private Type lobound = null; + + /** Constructor */ + public AbsTypeSymbol(int pos, Name name, Symbol owner, int flags) { + super(TYPE, pos, name, owner, flags); + } + + /** Return a fresh symbol with the same fields as this one. + */ + public Symbol cloneSymbol() { + if (Global.instance.debug) System.out.println("cloning " + this + this.locationString() + " in phase " + Global.instance.currentPhase.name()); + TypeSymbol other = new AbsTypeSymbol(pos, name, owner(), flags); + other.setInfo(info()); + other.setLoBound(loBound()); + return other; + } + + public Type loBound() { + initialize(); + return lobound == null ? Global.instance.definitions.ALL_TYPE : lobound; + } + + public Symbol setLoBound(Type lobound) { + this.lobound = lobound; + return this; + } +} + /** A class for class symbols. It has JavaClassSymbol as a subclass. */ public class ClassSymbol extends TypeSymbol { @@ -1377,6 +1429,10 @@ public final class ErrorSymbol extends Symbol { return this; } + public Type loBound() { + return Type.ErrorType; + } + public void reset(Type completer) { } } diff --git a/sources/scalac/symtab/Type.java b/sources/scalac/symtab/Type.java index d532db05c4..80e0823f97 100644 --- a/sources/scalac/symtab/Type.java +++ b/sources/scalac/symtab/Type.java @@ -489,6 +489,7 @@ public class Type implements Modifiers, Kinds, TypeTags { } /** Is this type a reference to an object type? + * todo: replace by this.isSubType(global.definitions.ANY_TYPE)? */ public boolean isObjectType() { switch (unalias()) { @@ -1266,7 +1267,10 @@ public class Type implements Modifiers, Kinds, TypeTags { case TypeRef(Type pre1, Symbol sym1, Type[] args1): switch (this) { case TypeRef(Type pre, Symbol sym, Type[] args): - if (sym == sym1 && pre.isSameAs(pre1) && isSubArgs(args, args1)) + if (sym == sym1 && pre.isSameAs(pre1) && + isSubArgs(args, args1, sym.typeParams()) + || + sym.kind == TYPE && pre.memberInfo(sym).isSubType(that)) return true; break; } @@ -1355,11 +1359,26 @@ public class Type implements Modifiers, Kinds, TypeTags { return constr.inst.isSubType(that); } else { constr.hibounds = new List(that.dropVariance(), constr.hibounds); + assert that.dropVariance().symbol() != Global.instance.definitions.ALL_CLASS;//debug return true; } case TypeRef(_, Symbol sym, _): - if (sym.kind == ALIAS) return this.unalias().isSubType(that); + switch (that) { + case TypeRef(Type pre1, Symbol sym1, _): + if (sym1.kind == TYPE && + this.isSubType( + sym1.loBound().asSeenFrom(pre1, sym1.owner()))) + return true; + } + if (sym.kind == ALIAS) + return this.unalias().isSubType(that); + else if (sym == Global.instance.definitions.ALL_CLASS) + return that.isSubType(Global.instance.definitions.ANY_TYPE); + else if (sym == Global.instance.definitions.ALLREF_CLASS) + return + that.isSameAs(Global.instance.definitions.ANY_TYPE) || + that.isSubType(Global.instance.definitions.ANYREF_TYPE); break; case OverloadedType(Symbol[] alts, Type[] alttypes): @@ -1390,7 +1409,7 @@ public class Type implements Modifiers, Kinds, TypeTags { /** Are types `these' arguments types conforming to corresponding types `those'? */ - static boolean isSubArgs(Type[] these, Type[] those) { + static boolean isSubArgs(Type[] these, Type[] those, Symbol[] tparams) { if (these.length != those.length) return false; for (int i = 0; i < these.length; i++) { switch (those[i]) { @@ -1404,8 +1423,12 @@ public class Type implements Modifiers, Kinds, TypeTags { } break; default: - if (these[i].isCovarType() || !these[i].isSameAs(those[i])) - return false; + if (these[i].isCovarType()) return false; + if ((tparams[i].flags & COVARIANT) != 0) { + if (!these[i].isSubType(those[i])) return false; + } else { + if (!these[i].isSameAs(those[i])) return false; + } } } return true; @@ -1811,7 +1834,8 @@ public class Type implements Modifiers, Kinds, TypeTags { static Type arglub(Type[] types) { Type pre = types[0].prefix(); Symbol sym = types[0].symbol(); - Type[] args = new Type[sym.typeParams().length]; + Symbol[] tparams = sym.typeParams(); + Type[] args = new Type[tparams.length]; Type[][] argss = new Type[args.length][types.length]; for (int i = 0; i < types.length; i++) { switch (types[i]) { @@ -1828,9 +1852,15 @@ public class Type implements Modifiers, Kinds, TypeTags { } } for (int j = 0; j < args.length; j++) { - args[j] = commonType(argss[j]); - if (args[j] == NoType) - args[j] = CovarType(lub(argss[j])); + if ((tparams[j].flags & COVARIANT) != 0) { + args[j] = commonType(argss[j]); + if (args[j] == NoType) + args[j] = lub(argss[j]); + } else { //todo: test if all same, return notype otherwise. + args[j] = commonType(argss[j]); + if (args[j] == NoType) + args[j] = CovarType(lub(argss[j])); + } } return typeRef(pre, sym, args); } @@ -1861,16 +1891,55 @@ public class Type implements Modifiers, Kinds, TypeTags { */ public static Type lub(Type[] tps) { //System.out.println("lub" + ArrayApply.toString(tps));//DEBUG + + // remove All and AllRef types + boolean all = false; + boolean allref = false; + for (int i = 0; i < tps.length; i++) { + if (!tps[i].isObjectType()) { + System.out.println("not an object type"); + return Type.NoType;//todo: change + } + all |= tps[i].symbol() == Global.instance.definitions.ALL_CLASS; + allref |= tps[i].symbol() == Global.instance.definitions.ALLREF_CLASS; + } + + if (all | allref) { + Type.List tl = Type.List.EMPTY; + for (int i = 0; i < tps.length; i++) { + if (tps[i].symbol() != Global.instance.definitions.ALL_CLASS && + tps[i].symbol() != Global.instance.definitions.ALLREF_CLASS) { + if (allref && + !tps[i].isSubType(Global.instance.definitions.ANYREF_TYPE)) + return Global.instance.definitions.ANY_TYPE; + else + tl = new Type.List(tps[i], tl); + } + } + if (tl == Type.List.EMPTY) { + return allref ? Global.instance.definitions.ALLREF_TYPE + : Global.instance.definitions.ALL_TYPE; + } + tps = tl.toArrayReverse(); + } + + // fast path if all types agree. Type lubType = commonType(tps); if (lubType != NoType) return lubType; + + // intersect closures and build frontier. Type[][] closures = new Type[tps.length][]; for (int i = 0; i < tps.length; i++) { - if (!tps[i].isObjectType()) return Type.NoType;//todo: change closures[i] = tps[i].closure(); } Type[] allBaseTypes = intersection(closures); Type[] leastBaseTypes = frontier(allBaseTypes); - if (leastBaseTypes.length == 0) return Type.NoType; + if (leastBaseTypes.length == 0) { + //System.out.println("empty intersection");//DEBUG + return Type.NoType; + } + + // add refinements where necessary Scope members = new Scope(); lubType = compoundType(leastBaseTypes, members); Type lubThisType = lubType.narrow(); @@ -1936,7 +2005,7 @@ public class Type implements Modifiers, Kinds, TypeTags { lubSym = new TermSymbol(syms[0].pos, syms[0].name, owner, 0); break; case TYPE: case ALIAS: case CLASS: - lubSym = new TypeSymbol(TYPE, syms[0].pos, syms[0].name, owner, 0); + lubSym = new AbsTypeSymbol(syms[0].pos, syms[0].name, owner, 0); break; default: throw new ApplicationError(); @@ -2022,10 +2091,9 @@ public class Type implements Modifiers, Kinds, TypeTags { Name fullname = sym.fullName(); if (fullname == Names.scala_Array && args.length == 1 /*&& args[0].unalias().symbol().kind != TYPE Q: why needed?*/) { - Global global = Global.instance; Type bound = args[0].bound(); - if (bound.symbol() != global.definitions.ANY_CLASS && - bound.symbol() != global.definitions.ANYVAL_CLASS) + if (bound.symbol() != Global.instance.definitions.ANY_CLASS && + bound.symbol() != Global.instance.definitions.ANYVAL_CLASS) { return UnboxedArrayType(args[0].erasure()); } @@ -2051,10 +2119,13 @@ public class Type implements Modifiers, Kinds, TypeTags { return pre.memberInfo(sym).erasure(); case CLASS: - if (Global.instance.definitions.UNIT_CLASS == sym) return this; - if (sym.fullName() == Names.java_lang_Object || - sym.fullName() == Names.scala_AnyRef || - sym.fullName() == Names.scala_AnyVal) + if (sym == Global.instance.definitions.UNIT_CLASS) return this; + Name fullname = sym.fullName(); + if (fullname == Names.java_lang_Object || + fullname == Names.scala_AnyRef || + fullname == Names.scala_AnyVal || + fullname == Names.scala_All || + fullname == Names.scala_AllRef) return Global.instance.definitions.ANY_TYPE; else { Type this1 = unbox(); diff --git a/sources/scalac/symtab/classfile/AttributeParser.java b/sources/scalac/symtab/classfile/AttributeParser.java index a6ae0a9083..dba5daa3de 100644 --- a/sources/scalac/symtab/classfile/AttributeParser.java +++ b/sources/scalac/symtab/classfile/AttributeParser.java @@ -187,7 +187,7 @@ public class AttributeParser implements ClassfileConstants { } Symbol s = tvars.lookup(Name.fromString(name).toTypeName()); if (s == Symbol.NONE) { - s = new TypeSymbol(Kinds.TYPE, + s = new AbsTypeSymbol( Position.NOPOS, Name.fromString(token).toTypeName(), owner, diff --git a/sources/scalac/transformer/AddInterfaces.java b/sources/scalac/transformer/AddInterfaces.java index 4c9cfd010f..e3d93217d8 100644 --- a/sources/scalac/transformer/AddInterfaces.java +++ b/sources/scalac/transformer/AddInterfaces.java @@ -482,7 +482,7 @@ class AddInterfaces extends SubstTransformer { List newBody = new LinkedList(); for (int i = 0; i < body.length; ++i) { switch (body[i]) { - case TypeDef(_, _, _): + case TypeDef(_, _, _, _): break; default: newBody.add(transform(body[i])); diff --git a/sources/scalac/transformer/Erasure.java b/sources/scalac/transformer/Erasure.java index e09189622f..a890c37498 100644 --- a/sources/scalac/transformer/Erasure.java +++ b/sources/scalac/transformer/Erasure.java @@ -350,7 +350,7 @@ public class Erasure extends Transformer implements Modifiers { Tree rhs1 = (rhs == Tree.Empty) ? rhs : transform(rhs, tpe1.type); return copy.ValDef(tree, tpe1, rhs1).setType(owntype); - case TypeDef(_, _, _): + case TypeDef(_, _, _, _): // eliminate return Tree.Empty; diff --git a/sources/scalac/transformer/LambdaLift.java b/sources/scalac/transformer/LambdaLift.java index bee9f9b896..537e1f19a8 100644 --- a/sources/scalac/transformer/LambdaLift.java +++ b/sources/scalac/transformer/LambdaLift.java @@ -207,13 +207,14 @@ public class LambdaLift extends OwnerTransformer } return super.transform(tree); - case TypeDef(_, _, Tree rhs): + case TypeDef(int mods, Name name, Tree rhs, Tree lobound): // ignore type definition as owner. // reason: it might be in a refinement // todo: handle type parameters? return copy.TypeDef( tree, sym, - transform(rhs, currentOwner)); + transform(rhs, currentOwner), + transform(lobound, currentOwner)); case Ident(_): if (sym.isLocal()) { @@ -353,12 +354,14 @@ public class LambdaLift extends OwnerTransformer transform(rhs, sym)); } - case TypeDef(_, _, Tree rhs): + case TypeDef(int mods, Name name, Tree rhs, Tree lobound): // ignore type definition as owner. // reason: it might be in a refinement // todo: handle type parameters? return copy.TypeDef( - tree, tree.symbol(), transform(rhs, currentOwner)); + tree, tree.symbol(), + transform(rhs, currentOwner), + transform(lobound, currentOwner)); case ValDef(_, _, Tree tpe, Tree rhs): Symbol sym = tree.symbol(); diff --git a/sources/scalac/transformer/OwnerTransformer.java b/sources/scalac/transformer/OwnerTransformer.java index 51711ed2da..66e68ff45b 100644 --- a/sources/scalac/transformer/OwnerTransformer.java +++ b/sources/scalac/transformer/OwnerTransformer.java @@ -127,11 +127,12 @@ public class OwnerTransformer extends Transformer { transform(tpe), transform(rhs, symbol)); - case TypeDef(_, _, Tree rhs): - Symbol symbol = tree.symbol(); + case TypeDef(int mods, Name name, Tree rhs, Tree lobound): + Symbol sym = tree.symbol(); return copy.TypeDef( - tree, symbol, - transform(rhs, symbol)); + tree, sym, + transform(rhs, sym), + transform(lobound, sym)); default: return super.transform(tree); diff --git a/sources/scalac/typechecker/Analyzer.java b/sources/scalac/typechecker/Analyzer.java index 4292e3b101..63d1c31317 100644 --- a/sources/scalac/typechecker/Analyzer.java +++ b/sources/scalac/typechecker/Analyzer.java @@ -467,6 +467,9 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { sym.flags |= LOCKED; checkNonCyclic( pos, pre.memberInfo(sym).subst(sym.typeParams(), args)); + if (sym.kind == TYPE) + checkNonCyclic( + pos, sym.loBound().asSeenFrom(pre, sym.owner())); sym.flags &= ~LOCKED; } break; @@ -671,6 +674,91 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { return msg + note; } +// 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 = clazz; + int flip = CoVariance; + while (sym != clazz && flip != AnyVariance) { + 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) { + error(sym.pos, + varianceString(sym.variance()) + " " + sym + + " occurs in " + f * variance + + " position in type " + all); + } + } + 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); + break; + case CovarType(Type tp1): + validateVariance(base, all, tp1, CoVariance); + } + } + + 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()); + } + // Entering Symbols ---------------------------------------------------------- Tree transformPackageId(Tree tree) { @@ -759,9 +847,11 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { case DefDef(int mods, Name name, _, _, _, _): return enterSym(tree, new TermSymbol(tree.pos, name, owner, mods)); - case TypeDef(int mods, Name name, _): - int kind = (mods & (DEFERRED | PARAM)) != 0 ? TYPE : ALIAS; - return enterSym(tree, new TypeSymbol(kind, tree.pos, name, owner, mods)); + case TypeDef(int mods, Name name, _, _): + Symbol tsym = ((mods & (DEFERRED | PARAM)) != 0) + ? new AbsTypeSymbol( tree.pos, name, owner, mods) + : new TypeSymbol(ALIAS, tree.pos, name, owner, mods); + return enterSym(tree, tsym); case Import(Tree expr, Name[] selectors): return enterImport(tree, @@ -882,7 +972,6 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { 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); @@ -964,12 +1053,13 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { //System.out.println("methtype " + name + ":" + owntype);//DEBUG break; - case TypeDef(int mods, Name name, Tree rhs): - //todo: alwyas have context.owner as owner. + case TypeDef(int mods, Name name, Tree rhs, Tree lobound): + //todo: always have context.owner as owner. if (sym.kind == TYPE) { 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(); } else { // sym.kind == ALIAS @@ -1014,8 +1104,9 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { templ.pos, templ.parents, true); Type[] parents = new Type[constrs.length]; - for (int i = 0; i < parents.length; i++) + for (int i = 0; i < parents.length; i++) { parents[i] = constrs[i].type; + } // enter all members Scope members = new Scope(); @@ -1830,12 +1921,16 @@ 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) .setType(definitions.UNIT_TYPE); @@ -1847,13 +1942,14 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { // rhs already attributed by defineSym in this case } else if (rhs != Tree.Empty) { if ((sym.flags & CASEACCESSOR) != 0) { - //rhs was already attribute + //rhs was already attributed } else { pushContext(tree, sym, context.scope); rhs1 = transform(rhs, EXPRmode, sym.type()); popContext(); } } + validateVariance(sym, sym.type(), CoVariance); return copy.ValDef(tree, sym, tpe1, rhs1) .setType(definitions.UNIT_TYPE); @@ -1874,16 +1970,19 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { tpe1.type == Type.NoType ? Type.AnyType : tpe1.type); } popContext(); + validateVariance(sym, sym.type(), CoVariance); return copy.DefDef(tree, sym, tparams1, vparams1, tpe1, rhs1) .setType(definitions.UNIT_TYPE); - case TypeDef(_, _, Tree rhs): + case TypeDef(_, _, Tree rhs, Tree lobound): pushContext(tree, sym, new Scope(context.scope)); int mode = TYPEmode; if (sym.kind == ALIAS) mode |= FUNmode; Tree rhs1 = transform(rhs, mode); + Tree lobound1 = transform(lobound, TYPEmode); popContext(); - return copy.TypeDef(tree, sym, rhs1) + validateVariance(sym, sym.info(), NoVariance); + return copy.TypeDef(tree, sym, rhs1, lobound1) .setType(definitions.UNIT_TYPE); case Import(Tree expr, Name[] selectors): diff --git a/sources/scalac/typechecker/AnalyzerPhase.java b/sources/scalac/typechecker/AnalyzerPhase.java index 3b34892fbe..1b36ccede7 100644 --- a/sources/scalac/typechecker/AnalyzerPhase.java +++ b/sources/scalac/typechecker/AnalyzerPhase.java @@ -35,7 +35,6 @@ public class AnalyzerPhase extends PhaseDescriptor { if (!global.noimports) { TreeFactory make = global.make; - Tree java = make.Ident(Position.NOPOS, Names.java) .setSymbol(definitions.JAVA) .setType(Type.singleType(definitions.ROOT_TYPE, definitions.JAVA)); diff --git a/sources/scalac/typechecker/Context.java b/sources/scalac/typechecker/Context.java index 3f1b30388f..5c01e9d73e 100644 --- a/sources/scalac/typechecker/Context.java +++ b/sources/scalac/typechecker/Context.java @@ -19,6 +19,7 @@ public class Context { Context outer; // The next outer 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() {} @@ -35,6 +36,7 @@ public class Context { if (tree instanceof Tree.Template || 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/Infer.java b/sources/scalac/typechecker/Infer.java index ac9da5b7df..d6bfe57384 100644 --- a/sources/scalac/typechecker/Infer.java +++ b/sources/scalac/typechecker/Infer.java @@ -548,12 +548,17 @@ public class Infer implements Modifiers, Kinds { for (int i = 0; i < argtypes.length; i++) { if (!isCompatible(argtypes[i].subst(tparams, tvars), formals[i].subst(tparams, tvars))) { - if (needToSucceed) + if (needToSucceed) { + Type.debugSwitch = true; + argtypes[i].subst(tparams, tvars).isSubType( + formals[i].subst(tparams, tvars)); + Type.debugSwitch = false; throw new NoInstance( typeErrorMsg( "argument expression's type is not compatible with formal parameter type", argtypes[i].subst(tparams, tvars), formals[i].subst(tparams, tvars))); + } return null; } } @@ -564,6 +569,7 @@ public class Infer implements Modifiers, Kinds { ? Type.NoType : instantiate(tvars[i]); } + //System.out.println(" = " + ArrayApply.toString(targs));//DEBUG return targs; } diff --git a/sources/scalac/typechecker/RefCheck.java b/sources/scalac/typechecker/RefCheck.java index 2728bdb6c3..0d5caa78e4 100644 --- a/sources/scalac/typechecker/RefCheck.java +++ b/sources/scalac/typechecker/RefCheck.java @@ -118,12 +118,6 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { return stats; } - public Tree nullTree(int pos, Type tp) { - return gen.TypeApply( - gen.Ident(pos, defs.NULL), - new Tree[]{gen.mkType(pos, tp)}); - } - private boolean isGlobalModule(Symbol sym) { return sym.isModule() && @@ -150,20 +144,20 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { Tree vdef = gen.ValDef(sym, alloc); return new Tree[]{cdef, vdef}; } else { - // var m$: T = null[T]; + // var m$: T = null; Name varname = Name.fromString(name + "$"); Symbol mvar = new TermSymbol( tree.pos, varname, sym.owner(), PRIVATE | MUTABLE | SYNTHETIC) .setInfo(sym.type()); - Tree vdef = gen.ValDef(mvar, nullTree(tree.pos, sym.type())); + Tree vdef = gen.ValDef(mvar, gen.Ident(tree.pos, defs.NULL)); - // { if (null[T] == m$) m$ = new m$class; m$ } + // { if (null == m$) m$ = new m$class; m$ } Symbol eqMethod = getMemberMethod( sym.type(), Names.EQEQ, defs.ANY_TYPE); Tree body = gen.Block(new Tree[]{ gen.If( gen.Apply( - gen.Select(nullTree(tree.pos, sym.type()), eqMethod), + gen.Select(gen.Ident(tree.pos, defs.NULL), eqMethod), new Tree[]{gen.mkRef(tree.pos, mvar)}), gen.Assign(gen.mkRef(tree.pos, mvar), alloc), gen.Block(tree.pos, Tree.EMPTY_ARRAY)), diff --git a/sources/scalac/util/Names.java b/sources/scalac/util/Names.java index 81b31b737c..4e5423c395 100644 --- a/sources/scalac/util/Names.java +++ b/sources/scalac/util/Names.java @@ -80,6 +80,8 @@ public class Names { 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"); public static final Name scala_AnyRef = Name.fromString("scala.AnyRef"); public static final Name scala_AnyVal = Name.fromString("scala.AnyVal"); diff --git a/test/files/pos/List1.scala b/test/files/pos/List1.scala index 6c54f109ce..f0fce9501f 100644 --- a/test/files/pos/List1.scala +++ b/test/files/pos/List1.scala @@ -9,8 +9,8 @@ object lists { def Nil[a] = new List[a] { def isEmpty: Boolean = true; - def head = error[a]("head of Nil"); - def tail = error[List[a]]("tail of Nil"); + def head = error("head of Nil"); + def tail = error("tail of Nil"); } def Cons[a](x: a, xs: List[a]): List[a] = new List[a] { diff --git a/test/files/pos/exceptions.scala b/test/files/pos/exceptions.scala index 7c376f3aac..c47b0e4785 100644 --- a/test/files/pos/exceptions.scala +++ b/test/files/pos/exceptions.scala @@ -7,7 +7,8 @@ object test { def main(): Unit = { try { try { - error("hi!"); + System.out.println("hi!"); + error("xx"); } finally { System.out.println("ho!") } @@ -18,4 +19,4 @@ object test { } main(); -}
\ No newline at end of file +} diff --git a/test/files/pos/expressions-current.scala b/test/files/pos/expressions-current.scala new file mode 100644 index 0000000000..207adb2b14 --- /dev/null +++ b/test/files/pos/expressions-current.scala @@ -0,0 +1,63 @@ +package test; + +abstract class Lang { + trait Visitor { + def caseNum(n: int): unit; + } + + abstract class Exp { + def visit(v: visitor): unit; + } + + type visitor <: Visitor; + + class Num(n: int) extends Exp { + def visit(v: visitor): unit = v.caseNum(n); + } + + class Eval(result: Ref[int]): visitor extends Visitor { + def caseNum(n: int) = result.elem = n; + } +} + +abstract class Lang2 extends Lang { + trait Visitor2 extends Visitor { + def casePlus(left: Exp, right: Exp): unit; + } + + type visitor <: Visitor2; + + class Plus(l: Exp, r: Exp) extends Exp { + def visit(v: visitor): unit = v.casePlus(l, r); + } + + class Eval2(result: Ref[int]): visitor extends Eval(result) with Visitor2 { + def casePlus(l: Exp, r: Exp) = + result.elem = { l.visit(this); result.elem } + { r.visit(this); result.elem } + } + + class Show2(result: Ref[String]): visitor extends Visitor2 { + def caseNum(n: int) = result.elem = n.toString(); + def casePlus(l: Exp, r: Exp) = + result.elem = + "(" + { l.visit(this); result.elem } + + "+" + { r.visit(this); result.elem }+ ")"; + } +} + +object Main { + + def main(args: Array[String]) = { + val l1 = new Lang { type visitor = Visitor } + val e1: l1.Exp = new l1.Num(42); + + val iref = new Ref(0); + System.out.println("eval: " + { e1.visit(new l1.Eval(iref)); iref.elem }); + + val l2 = new Lang2 { type visitor = Visitor2 } + val e2: l2.Exp = new l2.Plus(new l2.Num(5), new l2.Num(37)); + val sref = new Ref(""); + System.out.println("eval: " + { e2.visit(new l2.Eval2(iref)); iref.elem }); + System.out.println("show: " + { e2.visit(new l2.Show2(sref)); sref.elem }); + } +} diff --git a/test/files/pos/patterns3.scala b/test/files/pos/patterns3.scala new file mode 100644 index 0000000000..6caa834852 --- /dev/null +++ b/test/files/pos/patterns3.scala @@ -0,0 +1,5 @@ +module M { + + val Tuple2(Tuple2(x, y), _) = Tuple2(Tuple2(1, 2), 3); + +}
\ No newline at end of file diff --git a/test/files/pos/philippe4.scala b/test/files/pos/philippe4.scala new file mode 100644 index 0000000000..c9b1cdaeb0 --- /dev/null +++ b/test/files/pos/philippe4.scala @@ -0,0 +1,3 @@ +trait Foo[t <: Foo[t]]: t { + def foo(that: t): Boolean; +} diff --git a/test/files/pos/simplelists.scala b/test/files/pos/simplelists.scala new file mode 100644 index 0000000000..143bbdd77b --- /dev/null +++ b/test/files/pos/simplelists.scala @@ -0,0 +1,17 @@ + abstract class List[+a] { + def head: a; + def tail: List[a]; + def cons[b >: a](x: b): List[b] = new Cons[b, a](x, this); + } + + object Nil extends List[All] { + def error(msg: String): All = new java.lang.Error(msg).throw; + def head: All = error("Nil.head"); + def tail: List[All] = error("Nil.tail"); + } + + class Cons[c, d <: c](x: c, xs: List[d]) extends List[c] { + def head: c = x; + def tail: List[c] = xs; + } + diff --git a/test/pos/List1.scala b/test/pos/List1.scala index 6c54f109ce..f0fce9501f 100644 --- a/test/pos/List1.scala +++ b/test/pos/List1.scala @@ -9,8 +9,8 @@ object lists { def Nil[a] = new List[a] { def isEmpty: Boolean = true; - def head = error[a]("head of Nil"); - def tail = error[List[a]]("tail of Nil"); + def head = error("head of Nil"); + def tail = error("tail of Nil"); } def Cons[a](x: a, xs: List[a]): List[a] = new List[a] { diff --git a/test/pos/exceptions.scala b/test/pos/exceptions.scala index 7c376f3aac..c47b0e4785 100644 --- a/test/pos/exceptions.scala +++ b/test/pos/exceptions.scala @@ -7,7 +7,8 @@ object test { def main(): Unit = { try { try { - error("hi!"); + System.out.println("hi!"); + error("xx"); } finally { System.out.println("ho!") } @@ -18,4 +19,4 @@ object test { } main(); -}
\ No newline at end of file +} diff --git a/test/pos/expressions-current.scala b/test/pos/expressions-current.scala new file mode 100644 index 0000000000..207adb2b14 --- /dev/null +++ b/test/pos/expressions-current.scala @@ -0,0 +1,63 @@ +package test; + +abstract class Lang { + trait Visitor { + def caseNum(n: int): unit; + } + + abstract class Exp { + def visit(v: visitor): unit; + } + + type visitor <: Visitor; + + class Num(n: int) extends Exp { + def visit(v: visitor): unit = v.caseNum(n); + } + + class Eval(result: Ref[int]): visitor extends Visitor { + def caseNum(n: int) = result.elem = n; + } +} + +abstract class Lang2 extends Lang { + trait Visitor2 extends Visitor { + def casePlus(left: Exp, right: Exp): unit; + } + + type visitor <: Visitor2; + + class Plus(l: Exp, r: Exp) extends Exp { + def visit(v: visitor): unit = v.casePlus(l, r); + } + + class Eval2(result: Ref[int]): visitor extends Eval(result) with Visitor2 { + def casePlus(l: Exp, r: Exp) = + result.elem = { l.visit(this); result.elem } + { r.visit(this); result.elem } + } + + class Show2(result: Ref[String]): visitor extends Visitor2 { + def caseNum(n: int) = result.elem = n.toString(); + def casePlus(l: Exp, r: Exp) = + result.elem = + "(" + { l.visit(this); result.elem } + + "+" + { r.visit(this); result.elem }+ ")"; + } +} + +object Main { + + def main(args: Array[String]) = { + val l1 = new Lang { type visitor = Visitor } + val e1: l1.Exp = new l1.Num(42); + + val iref = new Ref(0); + System.out.println("eval: " + { e1.visit(new l1.Eval(iref)); iref.elem }); + + val l2 = new Lang2 { type visitor = Visitor2 } + val e2: l2.Exp = new l2.Plus(new l2.Num(5), new l2.Num(37)); + val sref = new Ref(""); + System.out.println("eval: " + { e2.visit(new l2.Eval2(iref)); iref.elem }); + System.out.println("show: " + { e2.visit(new l2.Show2(sref)); sref.elem }); + } +} diff --git a/test/pos/patterns3.scala b/test/pos/patterns3.scala new file mode 100644 index 0000000000..6caa834852 --- /dev/null +++ b/test/pos/patterns3.scala @@ -0,0 +1,5 @@ +module M { + + val Tuple2(Tuple2(x, y), _) = Tuple2(Tuple2(1, 2), 3); + +}
\ No newline at end of file diff --git a/test/pos/philippe4.scala b/test/pos/philippe4.scala new file mode 100644 index 0000000000..c9b1cdaeb0 --- /dev/null +++ b/test/pos/philippe4.scala @@ -0,0 +1,3 @@ +trait Foo[t <: Foo[t]]: t { + def foo(that: t): Boolean; +} diff --git a/test/pos/simplelists.scala b/test/pos/simplelists.scala new file mode 100644 index 0000000000..143bbdd77b --- /dev/null +++ b/test/pos/simplelists.scala @@ -0,0 +1,17 @@ + abstract class List[+a] { + def head: a; + def tail: List[a]; + def cons[b >: a](x: b): List[b] = new Cons[b, a](x, this); + } + + object Nil extends List[All] { + def error(msg: String): All = new java.lang.Error(msg).throw; + def head: All = error("Nil.head"); + def tail: List[All] = error("Nil.tail"); + } + + class Cons[c, d <: c](x: c, xs: List[d]) extends List[c] { + def head: c = x; + def tail: List[c] = xs; + } + |