summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2003-04-30 09:06:27 +0000
committerMartin Odersky <odersky@gmail.com>2003-04-30 09:06:27 +0000
commit21f24de326d79515c44f80665f9679410389b1ab (patch)
treebc8820c917f88ecda8469c90bd7f7298fdc27975
parente0d3451834b3cc5748dadb6b53971c05878faee4 (diff)
downloadscala-21f24de326d79515c44f80665f9679410389b1ab.tar.gz
scala-21f24de326d79515c44f80665f9679410389b1ab.tar.bz2
scala-21f24de326d79515c44f80665f9679410389b1ab.zip
*** empty log message ***
-rw-r--r--sources/meta/scalac/ast/Tree.java3
-rw-r--r--sources/scala/Except.scala4
-rw-r--r--sources/scala/Predef.scala7
-rw-r--r--sources/scala/Stream.scala2
-rw-r--r--sources/scalac/Global.java2
-rw-r--r--sources/scalac/ast/TreeGen.java3
-rw-r--r--sources/scalac/ast/TreeInfo.java6
-rw-r--r--sources/scalac/ast/parser/Parser.java62
-rw-r--r--sources/scalac/ast/printer/TextTreePrinter.java23
-rw-r--r--sources/scalac/backend/jvm/GenJVM.java2
-rw-r--r--sources/scalac/checkers/CheckOwners.java7
-rw-r--r--sources/scalac/symtab/Definitions.java38
-rw-r--r--sources/scalac/symtab/Symbol.java56
-rw-r--r--sources/scalac/symtab/Type.java109
-rw-r--r--sources/scalac/symtab/classfile/AttributeParser.java2
-rw-r--r--sources/scalac/transformer/AddInterfaces.java2
-rw-r--r--sources/scalac/transformer/Erasure.java2
-rw-r--r--sources/scalac/transformer/LambdaLift.java11
-rw-r--r--sources/scalac/transformer/OwnerTransformer.java9
-rw-r--r--sources/scalac/typechecker/Analyzer.java119
-rw-r--r--sources/scalac/typechecker/AnalyzerPhase.java1
-rw-r--r--sources/scalac/typechecker/Context.java2
-rw-r--r--sources/scalac/typechecker/Infer.java8
-rw-r--r--sources/scalac/typechecker/RefCheck.java14
-rw-r--r--sources/scalac/util/Names.java2
-rw-r--r--test/files/pos/List1.scala4
-rw-r--r--test/files/pos/exceptions.scala5
-rw-r--r--test/files/pos/expressions-current.scala63
-rw-r--r--test/files/pos/patterns3.scala5
-rw-r--r--test/files/pos/philippe4.scala3
-rw-r--r--test/files/pos/simplelists.scala17
-rw-r--r--test/pos/List1.scala4
-rw-r--r--test/pos/exceptions.scala5
-rw-r--r--test/pos/expressions-current.scala63
-rw-r--r--test/pos/patterns3.scala5
-rw-r--r--test/pos/philippe4.scala3
-rw-r--r--test/pos/simplelists.scala17
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;
+ }
+