summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2003-06-02 12:01:26 +0000
committerMartin Odersky <odersky@gmail.com>2003-06-02 12:01:26 +0000
commit6af6dae0df106de569e9b9cf503b3350722e58eb (patch)
tree07d2d19d6efb53f1eea6038bdd46ff0f9e74d06b
parent416062aa915f76195486e2400a2983c4cf372017 (diff)
downloadscala-6af6dae0df106de569e9b9cf503b3350722e58eb.tar.gz
scala-6af6dae0df106de569e9b9cf503b3350722e58eb.tar.bz2
scala-6af6dae0df106de569e9b9cf503b3350722e58eb.zip
*** empty log message ***
-rw-r--r--doc/reference/examples.verb.tex182
-rw-r--r--sources/scala/Array.java2
-rw-r--r--sources/scalac/ast/parser/Parser.java2
-rw-r--r--sources/scalac/symtab/Type.java386
-rw-r--r--sources/scalac/typechecker/Analyzer.java3
-rw-r--r--sources/scalac/typechecker/Infer.java301
-rw-r--r--test/files/run/lisp.scala10
7 files changed, 430 insertions, 456 deletions
diff --git a/doc/reference/examples.verb.tex b/doc/reference/examples.verb.tex
index 60036eb5ac..8aed1941c6 100644
--- a/doc/reference/examples.verb.tex
+++ b/doc/reference/examples.verb.tex
@@ -1329,7 +1329,7 @@ Scala does not have a built-in type of rational numbers, but it is
easy to define one, using a class. Here's a possible implementation.
\begin{verbatim}
-class Rational(n: int, d: int) with {
+class Rational(n: int, d: int) {
private def gcd(x: int, y: int): int = {
if (x == 0) y
else if (x < 0) gcd(-x, y)
@@ -1391,7 +1391,7 @@ If a class does not mention a superclass in its definition, the root
class \verb@Object@ is implicitly assumed. For instance, class
\verb@Rational@ could equivalently be defined as
\begin{verbatim}
-class Rational(n: int, d: int) extends Object with {
+class Rational(n: int, d: int) extends Object {
... // as before
}
\end{verbatim}
@@ -1411,7 +1411,7 @@ forms a string consisting of the object's class name and a number. It
makes sense to redefine this method for objects that are rational
numbers:
\begin{verbatim}
-class Rational(n: int, d: int) extends Object with {
+class Rational(n: int, d: int) extends Object {
... // as before
override def toString() = numer + "/" + denom;
}
@@ -1440,7 +1440,7 @@ Also unlike in Java, methods in Scala do not necessarily take a
parameter list. An example is the \verb@square@ method below. This
method is invoked by simply mentioning its name.
\begin{verbatim}
-class Rational(n: int, d: int) extends Object with {
+class Rational(n: int, d: int) extends Object {
... // as before
def square = Rational(numer*numer, denom*denom);
}
@@ -2839,7 +2839,7 @@ Classes in Scala can have type parameters. We demonstrate the use of
type parameters with iterators as an example. An iterator is an object
which traverses a sequence of values, using two abstract methods.
\begin{verbatim}
-abstract class Iterator[a] with {
+abstract class Iterator[a] {
def hasNext: boolean;
def next: a;
\end{verbatim}
@@ -2920,7 +2920,7 @@ inferred to be \verb@int@).
Method \verb@append@ constructs an iterator which resumes with the
given iterator \verb@it@ after the current iterator has finished.
\begin{verbatim}
- def append(that: Iterator[a]): Iterator[a] = new Iterator[a] with {
+ def append(that: Iterator[a]): Iterator[a] = new Iterator[a] {
def hasNext = outer.hasNext || that.hasNext;
def next = if (outer.hasNext) outer.next else that.next;
}
@@ -2938,8 +2938,8 @@ constructed by \verb@append@, which is not what we want.
Method \verb@filter@ constructs an iterator which returns all elements
of the original iterator that satisfy a criterion \verb@p@.
\begin{verbatim}
- def filter(p: a => boolean) = new Iterator[a] with {
- private class Cell[T](elem_: T) with { def elem = elem_; }
+ def filter(p: a => boolean) = new Iterator[a] {
+ private class Cell[T](elem_: T) { def elem = elem_; }
private var head: Cell[a] = null;
private var isAhead = false;
def hasNext: boolean =
@@ -2955,7 +2955,7 @@ of the original iterator that satisfy a criterion \verb@p@.
Method \verb@map@ constructs an iterator which returns all elements of
the original iterator transformed by a given function \verb@f@.
\begin{verbatim}
- def map[b](f: a => b) = new Iterator[b] with {
+ def map[b](f: a => b) = new Iterator[b] {
def hasNext: boolean = outer.hasNext;
def next: b = f(outer.next);
}
@@ -2985,7 +2985,7 @@ Finally, method \verb@zip@ takes another iterator and
returns an iterator consisting of pairs of corresponding elements
returned by the two iterators.
\begin{verbatim}
- def zip[b](that: Iterator[b]) = new Iterator[(a, b)] with {
+ def zip[b](that: Iterator[b]) = new Iterator[(a, b)] {
def hasNext = outer.hasNext && that.hasNext;
def next = (outer.next, that.next);
}
@@ -2996,7 +2996,7 @@ abstract methods \verb@next@ and \verb@hasNext@ in class
\verb@Iterator@. The simplest iterator is \verb@EmptyIterator@
which always returns an empty sequence:
\begin{verbatim}
-class EmptyIterator[a] extends Iterator[a] with {
+class EmptyIterator[a] extends Iterator[a] {
def hasNext = false;
def next: a = error("next on empty iterator");
}
@@ -3007,7 +3007,7 @@ have also been written as a class, like \verb@EmptyIterator@. The
difference between the two formulation is that classes also define new
types, whereas functions do not.
\begin{verbatim}
-def arrayIterator[a](xs: Array[a]) = new Iterator[a] with {
+def arrayIterator[a](xs: Array[a]) = new Iterator[a] {
private var i = 0;
def hasNext: boolean =
i < xs.length;
@@ -3018,7 +3018,7 @@ def arrayIterator[a](xs: Array[a]) = new Iterator[a] with {
\end{verbatim}
Another iterator enumerates an integer interval:
\begin{verbatim}
-def range(lo: int, hi: int) = new Iterator[int] with {
+def range(lo: int, hi: int) = new Iterator[int] {
private var i = lo;
def hasNext: boolean =
i <= hi;
@@ -3040,7 +3040,7 @@ iterator returns successive integers from some start
value\footnote{Due to the finite representation of type \prog{int},
numbers will wrap around at $2^31$.}.
\begin{verbatim}
-def from(start: int) = new Iterator[int] with {
+def from(start: int) = new Iterator[int] {
private var last = start - 1;
def hasNext = true;
def next = { last = last + 1; last }
@@ -3096,7 +3096,7 @@ Classes can also omit some of the definitions of their members. As an
example, consider the following class \verb@Ord@ which provides the
comparison operators \verb@<, >, <=, >=@.
%\begin{verbatim}
-%abstract class Ord with {
+%abstract class Ord {
% abstract def <(that: this);
% def <=(that: this) = this < that || this == that;
% def >(that: this) = that < this;
@@ -3104,7 +3104,7 @@ comparison operators \verb@<, >, <=, >=@.
%}
%\end{verbatim}
\begin{verbatim}
-abstract class Ord with {
+abstract class Ord {
def <(that: this): boolean;
def <=(that: this) = this < that || this == that;
def >(that: this) = that < this;
@@ -3131,7 +3131,7 @@ We can now define a class of \verb@Rational@ numbers that
support comparison operators.
\begin{verbatim}
final class OrderedRational(n: int, d: int)
- extends Rational(n, d) with Ord with {
+ extends Rational(n, d) with Ord {
override def ==(that: OrderedRational) =
numer == that.numer && denom == that.denom;
def <(that: OrderedRational): boolean =
@@ -3189,7 +3189,7 @@ Classes in Scala can have type parameters. We demonstrate the use of
type parameters with iterators as an example. An iterator is an object
which traverses a sequence of values, using two abstract methods.
\begin{verbatim}
-abstract class Iterator[a] with {
+abstract class Iterator[a] {
def hasNext: boolean;
def next: a;
\end{verbatim}
@@ -3212,7 +3212,7 @@ returning \verb@unit@ to each element returned by the iterator:
Method \verb@append@ constructs an iterator which resumes with the
given iterator \verb@it@ after the current iterator has finished.
\begin{verbatim}
- def append(that: Iterator[a]): Iterator[a] = new Iterator[a] with {
+ def append(that: Iterator[a]): Iterator[a] = new Iterator[a] {
def hasNext = outer.hasNext || that.hasNext;
def next = if (outer.hasNext) outer.next else that.next;
}
@@ -3230,8 +3230,8 @@ constructed by \verb@append@, which is not what we want.
Method \verb@filter@ constructs an iterator which returns all elements
of the original iterator that satisfy a criterion \verb@p@.
\begin{verbatim}
- def filter(p: a => boolean) = new Iterator[a] with {
- private class Cell[T](elem_: T) with { def elem = elem_; }
+ def filter(p: a => boolean) = new Iterator[a] {
+ private class Cell[T](elem_: T) { def elem = elem_; }
private var head: Cell[a] = null;
private var isAhead = false;
def hasNext: boolean =
@@ -3247,7 +3247,7 @@ of the original iterator that satisfy a criterion \verb@p@.
Method \verb@map@ constructs an iterator which returns all elements of
the original iterator transformed by a given function \verb@f@.
\begin{verbatim}
- def map[b](f: a => b) = new Iterator[b] with {
+ def map[b](f: a => b) = new Iterator[b] {
def hasNext: boolean = outer.hasNext;
def next: b = f(outer.next);
}
@@ -3277,7 +3277,7 @@ Finally, method \verb@zip@ takes another iterator and
returns an iterator consisting of pairs of corresponding elements
returned by the two iterators.
\begin{verbatim}
- def zip[b](that: Iterator[b]) = new Iterator[(a, b)] with {
+ def zip[b](that: Iterator[b]) = new Iterator[(a, b)] {
def hasNext = outer.hasNext && that.hasNext;
def next = (outer.next, that.next);
}
@@ -3288,7 +3288,7 @@ abstract methods \verb@next@ and \verb@hasNext@ in class
\verb@Iterator@. The simplest iterator is \verb@EmptyIterator@
which always returns an empty sequence:
\begin{verbatim}
-class EmptyIterator[a] extends Iterator[a] with {
+class EmptyIterator[a] extends Iterator[a] {
def hasNext = false;
def next: a = error("next on empty iterator");
}
@@ -3299,7 +3299,7 @@ have also been written as a class, like \verb@EmptyIterator@. The
difference between the two formulation is that classes also define new
types, whereas functions do not.
\begin{verbatim}
-def arrayIterator[a](xs: Array[a]) = new Iterator[a] with {
+def arrayIterator[a](xs: Array[a]) = new Iterator[a] {
private var i = 0;
def hasNext: boolean =
i < xs.length;
@@ -3310,7 +3310,7 @@ def arrayIterator[a](xs: Array[a]) = new Iterator[a] with {
\end{verbatim}
Another iterator enumerates an integer interval:
\begin{verbatim}
-def range(lo: int, hi: int) = new Iterator[int] with {
+def range(lo: int, hi: int) = new Iterator[int] {
private var i = lo;
def hasNext: boolean =
i <= hi;
@@ -3332,7 +3332,7 @@ iterator returns successive integers from some start
value\footnote{Due to the finite representation of type \prog{int},
numbers will wrap around at $2^31$.}.
\begin{verbatim}
-def from(start: int) = new Iterator[int] with {
+def from(start: int) = new Iterator[int] {
private var last = start - 1;
def hasNext = true;
def next = { last = last + 1; last }
@@ -3444,22 +3444,22 @@ database query languages. For instance, say we are given a book
database \verb@books@, represented as a list of books, where
\verb@Book@ is defined as follows.
\begin{verbatim}
-abstract class Book with {
+abstract class Book {
val title: String;
val authors: List[String]
}
\end{verbatim}
\begin{verbatim}
val books: List[Book] = [
- new Book with {
+ new Book {
val title = "Structure and Interpretation of Computer Programs";
val authors = ["Abelson, Harald", "Sussman, Gerald J."];
},
- new Book with {
+ new Book {
val title = "Principles of Compiler Design";
val authors = ["Aho, Alfred", "Ullman, Jeffrey"];
},
- new Book with {
+ new Book {
val title = "Programming in Modula-2";
val authors = ["Wirth, Niklaus"];
}
@@ -3603,7 +3603,7 @@ Note that the class \verb@Tree@ is not followed by an extends
clause or a body. This defines \verb@Tree@ to be an empty
subclass of \verb@Object@, as if we had written
\begin{verbatim}
-class Tree extends Object with {}
+class Tree extends Object {}
\end{verbatim}
Note also that the two subclasses of \verb@Tree@ have a \verb@case@
modifier. That modifier has two effects. First, it lets us construct
@@ -3671,7 +3671,7 @@ find(xs, x) match {
\comment{
-class MaxCounter with {
+class MaxCounter {
var maxVal: Option[int] = None;
def set(x: int) = maxVal match {
case None => maxVal = Some(x)
@@ -3684,7 +3684,7 @@ class MaxCounter with {
\begin{verbatim}
class Stream[a] = List[a]
-module Stream with {
+module Stream {
def concat(xss: Stream[Stream[a]]): Stream[a] = {
let result: Stream[a] = xss match {
case [] => []
@@ -3704,8 +3704,8 @@ three different styles: algebraic, object-oriented, and imperative.
In each case, a search tree package is seen as an implementation
of a class {\em MapStruct}.
\begin{verbatim}
-abstract class MapStruct[kt, vt] with {
- abstract type Map extends kt => vt with {
+abstract class MapStruct[kt, vt] {
+ abstract type Map extends kt => vt {
def apply(key: kt): vt;
def extend(key: kt, value: vt): Map;
def remove(key: kt): Map;
@@ -3734,12 +3734,12 @@ representation as the receiver object.
\begin{figure}[t]
\begin{verbatim}
-class AlgBinTree[kt extends Ord, vt] extends MapStruct[kt, vt] with {
+class AlgBinTree[kt extends Ord, vt] extends MapStruct[kt, vt] {
private case
Empty extends Map,
Node(key: kt, value: vt, l: Map, r: Map) extends Map
- final class Map extends kt => vt with {
+ final class Map extends kt => vt {
def apply(key: kt): vt = this match {
case Empty => null
case Node(k, v, l, r) =>
@@ -3809,22 +3809,22 @@ are constructed lazily.
\begin{figure}[thb]
\begin{verbatim}
-class OOBinTree[kt extends Ord, vt] extends MapStruct[kt, vt] with {
- abstract class Map extends kt => vt with {
+class OOBinTree[kt extends Ord, vt] extends MapStruct[kt, vt] {
+ abstract class Map extends kt => vt {
def apply(key: kt): v
def extend(key: kt, value: vt): Map
def remove(key: kt): Map
def domain: Stream[kt]
def range: Stream[vt]
}
- module empty extends Map with {
+ module empty extends Map {
def apply(key: kt) = null
def extend(key: kt, value: vt) = Node(key, value, empty, empty)
def remove(key: kt) = empty
def domain = []
def range = []
}
- private class Node(k: kt, v: vt, l: Map, r: Map) extends Map with {
+ private class Node(k: kt, v: vt, l: Map, r: Map) extends Map {
def apply(key: kt): vt =
if (key < k) l.apply(key)
else if (key > k) r.apply(key)
@@ -3877,8 +3877,8 @@ modified.
\begin{figure}
\begin{verbatim}
-class MutBinTree[kt extends Ord, vt] extends MapStruct[kt, vt] with {
- class Map(key: kt, value: vt) extends kt => vt with {
+class MutBinTree[kt extends Ord, vt] extends MapStruct[kt, vt] {
+ class Map(key: kt, value: vt) extends kt => vt {
val k = key
var v = value
var l = empty, r = empty
@@ -4029,7 +4029,7 @@ by a straightforward rewrite of the grammar, replacing \verb@::=@ with
Applying this process to the grammar of arithmetic
expressions yields:
\begin{verbatim}
-module ExprParser with {
+module ExprParser {
import Parse;
def letter \= = \= chrWith(c => c.isLetter);
@@ -4050,11 +4050,11 @@ is which underlying representation type to use for a parser. We treat
parsers here as functions that take a list of characters as input
parameter and that yield a parse result.
\begin{verbatim}
-module Parse with {
+module Parse {
type Result = Option[List[char]];
- abstract class Parser extends Function1[List[char],Result] with {
+ abstract class Parser extends Function1[List[char],Result] {
\end{verbatim}
\comment{
The \verb@Option@ type is predefined as follows.
@@ -4079,14 +4079,14 @@ method, as well as methods \verb@&&&@ and \verb@|||@.
abstract def apply(in: List[char]): Result;
\end{verbatim}
\begin{verbatim}
- def &&& (def p: Parser) = new Parser with {
+ def &&& (def p: Parser) = new Parser {
def apply(in: List[char]) = outer.apply(in) match {
case Some(in1) => p(in1)
case n => n
}
}
- def ||| (def p: Parser) = new Parser with {
+ def ||| (def p: Parser) = new Parser {
def apply(in: List[char]) = outer.apply(in) match {
case None => p(in)
case s => s
@@ -4098,11 +4098,11 @@ The implementations of the primitive parsers \verb@empty@, \verb@fail@,
\verb@chrWith@ and \verb@chr@ are as follows.
\begin{verbatim}
- def empty = new Parser with { def apply(in: List[char]) = Some(in) }
+ def empty = new Parser { def apply(in: List[char]) = Some(in) }
- def fail = new Parser with { def apply(in: List[char]) = None[List[char]] }
+ def fail = new Parser { def apply(in: List[char]) = None[List[char]] }
- def chrWith(p: char => boolean) = new Parser with {
+ def chrWith(p: char => boolean) = new Parser {
def apply(in: List[char]) = in match {
case [] => None[List[char]]
case (c :: in1) => if (p(c)) Some(in1) else None[List[char]]
@@ -4233,7 +4233,7 @@ We now present the parser combinators that support the new
scheme. Parsers that succeed now return a parse result besides the
un-consumed input.
\begin{verbatim}
-module Parse with {
+module Parse {
type Result[a] = Option[(a, List[char])]
\end{verbatim}
@@ -4245,32 +4245,32 @@ Chapter~\ref{sec:for-notation}.
Here is the complete definition of the new \verb@Parser@ class.
\begin{verbatim}
- abstract class Parser[a] extends Function1[List[char],Result[a]] with {
+ abstract class Parser[a] extends Function1[List[char],Result[a]] {
def apply(in: List[char]): Result[a];
- def filter(p: a => boolean) = new Parser[a] with {
+ def filter(p: a => boolean) = new Parser[a] {
def apply(in: List[char]): Result[a] = outer.apply(in) match {
case Some((x, in1)) => if (p(x)) Some((x, in1)) else None
case None => None
}
}
- def map[b](f: a => b) = new Parser[b] with {
+ def map[b](f: a => b) = new Parser[b] {
def apply(in: List[char]): Result[b] = outer.apply(in) match {
case Some((x, in1)) => Some((f(x), in1))
case None => None
}
}
- def flatMap[b](f: a => Parser[b]) = new Parser[b] with {
+ def flatMap[b](f: a => Parser[b]) = new Parser[b] {
def apply(in: List[char]): Result[b] = outer.apply(in) match {
case Some((x, in1)) => f(x)(in1)
case None => None
}
}
- def ||| (def p: Parser[a]) = new Parser[a] with {
+ def ||| (def p: Parser[a]) = new Parser[a] {
def apply(in: List[char]): Result[a] = outer.apply(in) match {
case None => p(in)
case s => s
@@ -4296,9 +4296,9 @@ the current parser and then continues with the resulting parser. The
% Here is the code for fail, chrWith and chr
%
%\begin{verbatim}
-% def fail[a] = new Parser[a] with { def apply(in: List[char]) = None[(a,List[char])] }
+% def fail[a] = new Parser[a] { def apply(in: List[char]) = None[(a,List[char])] }
%
-% def chrWith(p: char => boolean) = new Parser[char] with {
+% def chrWith(p: char => boolean) = new Parser[char] {
% def apply(in: List[char]) = in match {
% case [] => None[(char,List[char])]
% case (c :: in1) => if (p(c)) Some((c,in1)) else None[(char,List[char])]
@@ -4310,7 +4310,7 @@ the current parser and then continues with the resulting parser. The
The primitive parser \verb@succeed@ replaces \verb@empty@. It consumes
no input and returns its parameter as result.
\begin{verbatim}
- def succeed[a](x: a) = new Parser[a] with {
+ def succeed[a](x: a) = new Parser[a] {
def apply(in: List[char]) = Some((x, in))
}
\end{verbatim}
@@ -4356,7 +4356,7 @@ program.
The next data type describes the form of types that are
computed by the inference system.
\begin{verbatim}
-module Types with {
+module Types {
abstract final class Type;
case class Tyvar(a: String) extends Type;
case class Arrow(t1: Type, t2: Type) extends Type;
@@ -4398,7 +4398,7 @@ Even though there is only one possible way to construct a type scheme,
a \verb@case class@ representation was chosen since it offers a convenient
way to decompose a type scheme into its parts using pattern matching.
\begin{verbatim}
-case class TypeScheme(ls: List[String], t: Type) with {
+case class TypeScheme(ls: List[String], t: Type) {
def newInstance: Type = {
val instSubst =
((EmptySubst: Subst) :_foldl ls) { s, a => s.extend(Tyvar(a), newTyvar) }
@@ -4417,18 +4417,18 @@ type variables unchanged. The meaning of a substitution is extended
point-wise to a mapping from types to types.
\begin{verbatim}
-abstract class Subst extends Function1[Type,Type] with {
+abstract class Subst extends Function1[Type,Type] {
def lookup(x: Tyvar): Type;
def apply(t: Type): Type = t match {
case Tyvar(a) => val u = lookup(Tyvar(a)); if (t == u) t else apply(u);
case Arrow(t1, t2) => Arrow(apply(t1), apply(t2))
case Tycon(k, ts) => Tycon(k, ts map apply)
}
- def extend(x: Tyvar, t: Type) = new Subst with {
+ def extend(x: Tyvar, t: Type) = new Subst {
def lookup(y: Tyvar): Type = if (x == y) t else outer.lookup(y);
}
}
-case class EmptySubst extends Subst with { def lookup(t: Tyvar): Type = t }
+case class EmptySubst extends Subst { def lookup(t: Tyvar): Type = t }
\end{verbatim}
We represent substitutions as functions, of type
\verb@Type => Type@. To be an instance of this type, a
@@ -4446,7 +4446,7 @@ membership tests as well as \verb@union@ and \verb@diff@ for set union
and difference. Alternatively, one could have used a more efficient
implementation of sets in some standard library.
\begin{verbatim}
-class ListSet[a](xs: List[a]) with {
+class ListSet[a](xs: List[a]) {
val elems: List[a] = xs;
def contains(y: a): boolean = xs match {
@@ -4475,7 +4475,7 @@ computes a type for a given term in a given environment. Environments
associate variable names with type schemes. They are represented by a
type alias \verb@Env@ in module \verb@TypeChecker@:
\begin{verbatim}
-module TypeChecker with {
+module TypeChecker {
/** Type environments are lists of bindings that associate a
* name with a type scheme.
@@ -4612,7 +4612,7 @@ bindings for booleans, numbers and lists together with some primitive
operations over these types. It also defines a fixed point operator
\verb@fix@, which can be used to represent recursion.
\begin{verbatim}
-module Predefined with {
+module Predefined {
val booleanType = Tycon("Boolean", []);
val intType = Tycon("Int", []);
def listType(t: Type) = Tycon("List", [t]);
@@ -4666,7 +4666,7 @@ how they can be implemented in Scala.
The {\em monitor} provides the basic means for mutual exclusion
of processes in Scala. It is defined as follows.
\begin{verbatim}
-class Monitor with {
+class Monitor {
def synchronized [a] (def e: a): a;
}
\end{verbatim}
@@ -4683,7 +4683,7 @@ other thread. Calls to \verb@send@ with no threads waiting for the
signal are ignored. Here is the specification of the \verb@Signal@
class.
\begin{verbatim}
-class Signal with {
+class Signal {
def wait: unit;
def wait(msec: long): unit;
def notify: unit;
@@ -4700,7 +4700,7 @@ Scala which are implemented in terms of the underlying runtime system.
As an example of how monitors and signals are used, here is is an
implementation of a bounded buffer class.
\begin{verbatim}
-class BoundedBuffer[a](N: int) extends Monitor with {
+class BoundedBuffer[a](N: int) extends Monitor {
var in = 0, out = 0, n = 0;
val elems = new Array[a](N);
val nonEmpty = new Signal;
@@ -4733,7 +4733,7 @@ The \verb@fork@ method spawns a new thread which executes the
expression given in the parameter. It can be defined as follows.
\begin{verbatim}
def fork(def e: unit) = {
- val p = new Thread with { def run = e; }
+ val p = new Thread { def run = e; }
p.run
}
\end{verbatim}
@@ -4749,7 +4749,7 @@ blocks until the variable has been defined.
Logic variables can be implemented as follows.
\begin{verbatim}
-class LVar[a] extends Monitor with {
+class LVar[a] extends Monitor {
private val defined = new Signal
private var isDefined: boolean = false
private var v: a
@@ -4773,7 +4773,7 @@ resets the variable to undefined state.
Synchronized variables can be implemented as follows.
\begin{verbatim}
-class SyncVar[a] extends Monitor with {
+class SyncVar[a] extends Monitor {
private val defined = new Signal;
private var isDefined: boolean = false;
private var value: a;
@@ -4878,7 +4878,7 @@ A common mechanism for process synchronization is a {\em lock} (or:
\prog{release}. Here's the implementation of a lock in Scala:
\begin{verbatim}
-class Lock extends Monitor with Signal with {
+class Lock extends Monitor with Signal {
var available = true;
def acquire = {
if (!available) wait;
@@ -4908,7 +4908,7 @@ The following implementation of a readers/writers lock is based on the
{\em message space} concept (see Section~\ref{sec:messagespace}).
\begin{verbatim}
-class ReadersWriters with {
+class ReadersWriters {
val m = new MessageSpace;
private case class Writers(n: int), Readers(n: int);
Writers(0); Readers(0);
@@ -4939,7 +4939,7 @@ A fundamental way of interprocess communication is the asynchronous
channel. Its implementation makes use the following class for linked
lists:
\begin{verbatim}
-class LinkedList[a](x: a) with {
+class LinkedList[a](x: a) {
val elem: a = x;
var next: LinkedList[a] = null;
}
@@ -4953,7 +4953,7 @@ The channel class uses a linked list to store data that has been sent
but not read yet. In the opposite direction, a signal \verb@moreData@ is
used to wake up reader threads that wait for data.
\begin{verbatim}
-class Channel[a] with {
+class Channel[a] {
private val written = new LinkedList[a](null);
private var lastWritten = written;
private val moreData = new Signal;
@@ -4979,7 +4979,7 @@ a message blocks until that message has been received. Synchronous
channels only need a single variable to store messages in transit, but
three signals are used to coordinate reader and writer processes.
\begin{verbatim}
-class SyncChannel[a] with {
+class SyncChannel[a] {
val data = new SyncVar[a];
def write(x: a): unit = synchronized {
@@ -5014,7 +5014,7 @@ processor.
\begin{verbatim}
class ComputeServer(n: int) {
- private abstract class Job with {
+ private abstract class Job {
abstract type t;
def task: t;
def return(x: t): unit;
@@ -5033,7 +5033,7 @@ class ComputeServer(n: int) {
def future[a](def p: a): () => a = {
val reply = new SyncVar[a];
openJobs.write(
- new Job with {
+ new Job {
type t = a;
def task = p;
def return(x: a) = reply.set(x);
@@ -5088,7 +5088,7 @@ case class TIMEOUT;
\end{verbatim}
Message spaces implement the following signature.
\begin{verbatim}
-class MessageSpace with {
+class MessageSpace {
def send(msg: Any): unit;
def receive[a](f: PartialFunction[Any, a]): a;
def receiveWithin[a](msec: long)(f: PartialFunction[Any, a]): a;
@@ -5112,7 +5112,7 @@ time.
As a simple example of how message spaces are used, consider a
one-place buffer:
\begin{verbatim}
-class OnePlaceBuffer with {
+class OnePlaceBuffer {
private val m = new MessageSpace; \=// An internal message space
private case class Empty, Full(x: int); \>// Types of messages we deal with
@@ -5127,9 +5127,9 @@ class OnePlaceBuffer with {
\end{verbatim}
Here's how the message space class can be implemented:
\begin{verbatim}
-class MessageSpace with {
+class MessageSpace {
- private abstract class Receiver extends Signal with {
+ private abstract class Receiver extends Signal {
def isDefined(msg: Any): boolean;
var msg = null;
}
@@ -5177,7 +5177,7 @@ Otherwise, the message is appended to the linked list of sent messages.
s.next = s1.next; s1.elem
} else {
val r = new LinkedList(
- new Receiver with {
+ new Receiver {
def isDefined(msg: Any) = f.isDefined(msg);
});
lastReceiver.next = r; lastReceiver = r;
@@ -5213,7 +5213,7 @@ with the special \verb@TIMEOUT@ message. The implementation of
s.next = s1.next; s1.elem
} else {
val r = new LinkedList(
- new Receiver with {
+ new Receiver {
def isDefined(msg: Any) = f.isDefined(msg);
}
)
@@ -5268,7 +5268,7 @@ case class
\begin{verbatim}
class Auction(seller: Process, minBid: int, closing: Date)
- extends Process with {
+ extends Process {
val timeToShutdown = 36000000 // msec
val delta = 10 // bid increment
@@ -5336,7 +5336,7 @@ class Auction(seller: Process, minBid: int, closing: Date)
\end{verbatim}
\begin{verbatim}
class Bidder (auction: Process, minBid: int, maxBid: int)
- extends Process with {
+ extends Process {
val MaxTries = 3
val Unknown = -1
@@ -5451,7 +5451,7 @@ def sort(a:Array[String]): Array[String] = {
sort1(0, a.length - 1)
}
-class Array[a] with {
+class Array[a] {
def copy(to: Array[a], src: int, dst: int, len: int): unit
val length: int
diff --git a/sources/scala/Array.java b/sources/scala/Array.java
index 657210603e..fda73df7a1 100644
--- a/sources/scala/Array.java
+++ b/sources/scala/Array.java
@@ -13,7 +13,7 @@ package scala;
/** @meta class [?T] extends scala.Function1[scala.Int, ?T];
*/
-public abstract class Array implements Function1 {
+public abstract class Array implements Function1, Cloneable, java.io.Serializable {
/** @meta constr (scala.Int);
*/
diff --git a/sources/scalac/ast/parser/Parser.java b/sources/scalac/ast/parser/Parser.java
index 7a4d5a12fe..8c478044fc 100644
--- a/sources/scalac/ast/parser/Parser.java
+++ b/sources/scalac/ast/parser/Parser.java
@@ -1308,6 +1308,8 @@ public class Parser implements Tokens {
s.nextToken();
mods |= Modifiers.COVARIANT;
} else if (s.name == MINUS) {
+// syntaxError(
+// "contravariant type parameters not yet supported", false);
s.nextToken();
mods |= Modifiers.CONTRAVARIANT;
}
diff --git a/sources/scalac/symtab/Type.java b/sources/scalac/symtab/Type.java
index 511edd779c..4b5315c418 100644
--- a/sources/scalac/symtab/Type.java
+++ b/sources/scalac/symtab/Type.java
@@ -18,8 +18,6 @@ public class Type implements Modifiers, Kinds, TypeTags {
public static boolean debugSwitch = false;
private static int indent = 0;
- //todo: convert C with {} to C.
-
public case ErrorType; // not used after analysis
public case AnyType; // not used after analysis
public case NoType;
@@ -27,14 +25,10 @@ public class Type implements Modifiers, Kinds, TypeTags {
public case ThisType(Symbol sym);
public case TypeRef(Type pre, Symbol sym, Type[] args) {
- //assert sym != Global.instance.definitions.ALL_CLASS ||
- // Global.instance.definitions.ALL_TYPE == null;
assert pre.isLegalPrefix() || pre == ErrorType : pre + "#" + sym;
}
public case SingleType(Type pre, Symbol sym) {
- // assert sym != Global.instance.definitions.SCALA ||
- // Global.instance.definitions.SCALA_TYPE == null;
assert this instanceof ExtSingleType;
}
@@ -76,9 +70,6 @@ public class Type implements Modifiers, Kinds, TypeTags {
/** An empty Type array */
public static final Type[] EMPTY_ARRAY = new Type[0];
- /** A non-existing Type array; used to express type erasure */
- public static final Type[] NO_ARRAY = new Type[0];
-
public static SingleType singleType(Type pre, Symbol sym) {
if (pre.isStable() || pre == ErrorType) {
return new ExtSingleType(pre, sym);
@@ -132,28 +123,13 @@ public class Type implements Modifiers, Kinds, TypeTags {
ExtSingleType(Type pre, Symbol sym) {
super(pre, sym);
}
- private Type type() {
+ public Type singleDeref() {
if (definedId != Global.instance.currentPhase.id) {
definedId = Global.instance.currentPhase.id;
tp = pre.memberType(sym).resultType();
}
return tp;
}
- /** If this type is a thistype or singleton type, its underlying object type,
- * otherwise the type itself.
- */
- public Type widen() {
- return type().widen();
- }
-
- /** If this type is a singleton type whose type is another, the end of the chain,
- * otherwise the type itself.
- */
- public Type aliasedType() {
- Type tp = type();
- if (tp.isStable()) return tp.aliasedType();
- else return this;
- }
}
static class ExtCompoundType extends CompoundType {
@@ -205,10 +181,10 @@ public class Type implements Modifiers, Kinds, TypeTags {
return syms;
}
- /** If this type is a thistype or singleton type, its underlying object type,
+ /** If this type is a thistype or singleton type, its type,
* otherwise the type itself.
*/
- public Type widen() {
+ public Type singleDeref() {
switch (this) {
case ThisType(Symbol sym):
return sym.typeOfThis();
@@ -216,47 +192,35 @@ public class Type implements Modifiers, Kinds, TypeTags {
// overridden in ExtSingleType
throw new ApplicationError();
case TypeVar(Type origin, Constraint constr):
- if (constr.inst != NoType) return constr.inst.widen();
+ if (constr.inst != NoType) return constr.inst.singleDeref();
else return this;
default:
return this;
}
}
- public static Type[] widen(Type[] tps) {
- if (tps.length == 0) return Type.EMPTY_ARRAY;
- Type[] tps1 = new Type[tps.length];
- for (int i = 0; i < tps1.length; i++) {
- tps1[i] = tps[i].widen();
- assert !(tps1[i] instanceof SingleType) : tps[i];//debug
- }
- return tps1;
- }
-
- /** If this type is a singleton type whose type is another, the end of the chain,
+ /** If this type is a thistype or singleton type, its underlying object type,
* otherwise the type itself.
*/
- public Type aliasedType() {
- return this;
+ public Type widen() {
+ Type tp = singleDeref();
+ switch (tp) {
+ case ThisType(_):
+ case SingleType(_, _):
+ return tp.widen();
+ default:
+ return tp;
+ }
}
- /** The lower approximation of this type (which must be a typeref)
- */
- public Type loBound() {
- switch (unalias()) {
- case TypeRef(Type pre, Symbol sym, Type[] args):
- Type lb = Global.instance.definitions.ALL_TYPE;
- if (sym.kind == TYPE) {
- lb = sym.loBound().asSeenFrom(pre, sym.owner());
- }
- if (lb.symbol() == Global.instance.definitions.ALL_CLASS &&
- this.isSubType(Global.instance.definitions.ANYREF_TYPE)) {
- lb = Global.instance.definitions.ALLREF_TYPE;
+ private static Map widenMap = new Map() {
+ public Type apply(Type t) {
+ return t.widen();
}
- return lb;
- default:
- throw new ApplicationError();
- }
+ };
+
+ public static Type[] widen(Type[] tps) {
+ return widenMap.map(tps);
}
/** The thistype or singleton type corresponding to values of this type.
@@ -274,18 +238,26 @@ public class Type implements Modifiers, Kinds, TypeTags {
}
}
- /** The upper bound of this type.
- */
- public Type bound() {
- switch (this) {
+ /** The lower approximation of this type (which must be a typeref)
+ */
+ public Type loBound() {
+ switch (unalias()) {
case TypeRef(Type pre, Symbol sym, Type[] args):
- if (sym.kind == ALIAS || sym.kind == TYPE)
- return pre.memberInfo(sym).bound();
+ Type lb = Global.instance.definitions.ALL_TYPE;
+ if (sym.kind == TYPE) {
+ lb = pre.memberLoBound(sym);
+ }
+ if (lb.symbol() == Global.instance.definitions.ALL_CLASS &&
+ this.isSubType(Global.instance.definitions.ANYREF_TYPE)) {
+ lb = Global.instance.definitions.ALLREF_TYPE;
+ }
+ return lb;
+ default:
+ throw new ApplicationError();
}
- return this;
}
- /** The this is a this-type, named-type, applied type or single-type, its prefix,
+ /** If this is a this-type, named-type, applied type or single-type, its prefix,
* otherwise NoType.
*/
public Type prefix() {
@@ -312,14 +284,15 @@ public class Type implements Modifiers, Kinds, TypeTags {
}
/** Get type of `this' symbol corresponding to this type, extend
- * homomorphically to function types and method types.
+ * homomorphically to function types and poly types.
*/
public Type instanceType() {
switch (unalias()) {
case TypeRef(Type pre, Symbol sym, Type[] args):
- Type tp1 = sym.typeOfThis();
- if (tp1 != sym.type())
- return tp1.asSeenFrom(pre, sym.owner()).subst(sym.typeParams(), args);
+ if (sym != sym.thisSym())
+ return sym.typeOfThis()
+ .asSeenFrom(pre, sym.owner())
+ .subst(sym.typeParams(), args);
break;
case MethodType(Symbol[] params, Type restp):
Type restp1 = restp.instanceType();
@@ -344,7 +317,8 @@ public class Type implements Modifiers, Kinds, TypeTags {
}
private Type unalias(int n) {
- if (n == 20) throw new Type.Error("recursive type alias: " + this);
+ if (n == 100)
+ throw new Type.Error("alias chain too long (recursive type alias?): " + this);
switch (this) {
case TypeRef(Type pre, Symbol sym, Type[] args):
if (sym.kind == ALIAS) return pre.memberInfo(sym).unalias(n + 1);
@@ -356,13 +330,13 @@ public class Type implements Modifiers, Kinds, TypeTags {
return this;
}
- /** The (prefix-adapted) parents of this type.
+ /** The (prefix/argument-adapted) parents of this type.
*/
public Type[] parents() {
switch (unalias()) {
case ThisType(_):
case SingleType(_, _):
- return widen().parents();
+ return singleDeref().parents();
case TypeRef(Type pre, Symbol sym, Type[] args):
if (sym.kind == ALIAS)
return unalias().parents();
@@ -379,7 +353,7 @@ public class Type implements Modifiers, Kinds, TypeTags {
}
}
- /** Get type parameters of polymorphic method
+ /** Get type parameters of polymorphic method or class
* or EMPTY_ARRAY if not applicable.
*/
public Symbol[] typeParams() {
@@ -393,7 +367,7 @@ public class Type implements Modifiers, Kinds, TypeTags {
return Symbol.EMPTY_ARRAY;
}
- /** Get value parameters of method or EMPTY_ARRAY if not
+ /** Get value parameters of method or class or EMPTY_ARRAY if not
* applicable.
*/
public Symbol[] valueParams() {
@@ -527,10 +501,8 @@ public class Type implements Modifiers, Kinds, TypeTags {
public boolean isFunctionType() {
switch (this) {
case TypeRef(Type pre, Symbol sym, Type[] args):
- if (sym.fullName().startsWith(Names.scala_Function)) {
- return args.length > 0;
- }
- break;
+ return sym.fullName().startsWith(Names.scala_Function) &&
+ args.length > 0;
case CompoundType(Type[] parents, Scope members):
return members.elems == Scope.Entry.NONE &&
parents.length == 2 &&
@@ -552,7 +524,7 @@ public class Type implements Modifiers, Kinds, TypeTags {
case TypeRef(_, Symbol sym, _):
return sym.info().members();
case SingleType(_, Symbol sym):
- return widen().members();
+ return singleDeref().members();
case CompoundType(Type[] basetypes, Scope members):
return members;
default:
@@ -569,7 +541,7 @@ public class Type implements Modifiers, Kinds, TypeTags {
return Symbol.ERROR;
case ThisType(_):
case SingleType(_, _):
- return widen().lookup(name);
+ return singleDeref().lookup(name);
case TypeRef(_, Symbol sym, _):
return sym.info().lookup(name);
case CompoundType(Type[] parts, Scope members):
@@ -598,7 +570,7 @@ public class Type implements Modifiers, Kinds, TypeTags {
return Symbol.ERROR;
case ThisType(_):
case SingleType(_, _):
- return widen().lookupNonPrivate(name);
+ return singleDeref().lookupNonPrivate(name);
case TypeRef(_, Symbol sym, _):
return sym.info().lookupNonPrivate(name, start);
case CompoundType(Type[] parts, Scope members):
@@ -788,7 +760,7 @@ public class Type implements Modifiers, Kinds, TypeTags {
case ThisType(_):
case SingleType(_, _):
- return widen().baseType(clazz);
+ return singleDeref().baseType(clazz);
case TypeRef(Type pre, Symbol sym, Type[] args):
if (sym == clazz)
@@ -811,7 +783,8 @@ public class Type implements Modifiers, Kinds, TypeTags {
break;
case UnboxedArrayType(_):
- if (clazz == Global.instance.definitions.ANY_CLASS)
+ if (clazz == Global.instance.definitions.ANY_CLASS ||
+ clazz == Global.instance.definitions.ANYREF_CLASS)
return clazz.type();
}
return NoType;
@@ -840,29 +813,22 @@ public class Type implements Modifiers, Kinds, TypeTags {
this.pre = pre; this.clazz = clazz;
}
- public Type apply0(Type t) {
- Type t1 = apply0(t);
- System.out.println(t + " as seen from (" + pre + "," + clazz + ") = " + t1);//debug
- return t1;
- }
-
public Type apply(Type t) {
if (pre == NoType || clazz.kind != CLASS)
return t;
switch (t) {
case ThisType(Symbol sym):
- return t.toPrefix(pre, clazz);
+ return t.toPrefix(sym, pre, clazz);
case TypeRef(Type prefix, Symbol sym, Type[] args):
if (sym.kind == ALIAS) {
return apply(t.unalias());
} else if (sym.owner().isPrimaryConstructor()) {
assert sym.kind == TYPE;
- Type t1 = t.toInstance(pre, clazz);
+ Type t1 = t.toInstance(sym, pre, clazz);
//System.out.println(t + ".toInstance(" + pre + "," + clazz + ") = " + t1);//DEBUG
return t1;
} else {
- //Type prefix1 = prefix.toPrefix(pre, clazz);
Type prefix1 = apply(prefix);
Symbol sym1 = (prefix1 == prefix || (sym.flags & MODUL) != 0)
? sym : prefix1.rebind(sym);
@@ -873,12 +839,11 @@ public class Type implements Modifiers, Kinds, TypeTags {
case SingleType(Type prefix, Symbol sym):
try {
- //Type prefix1 = prefix.toPrefix(pre, clazz);
Type prefix1 = apply(prefix);
if (prefix1 == prefix) return t;
else return singleType(prefix1, prefix1.rebind(sym));
} catch (Type.Error ex) {}
- return apply(t.widen());
+ return apply(t.singleDeref());
default:
return map(t);
@@ -886,10 +851,9 @@ public class Type implements Modifiers, Kinds, TypeTags {
}
}
//where
- Type toInstance(Type pre, Symbol clazz) {
+ Type toInstance(Symbol sym, Type pre, Symbol clazz) {
if (pre == NoType || clazz.kind != CLASS)
return this;
- Symbol sym = symbol();
Symbol ownclass = sym.owner().primaryConstructorClass();
if (ownclass.isSubClass(clazz) &&
pre.widen().symbol().isSubClass(ownclass)) {
@@ -906,23 +870,23 @@ public class Type implements Modifiers, Kinds, TypeTags {
throw new ApplicationError(
this + " in " + ownclass + " cannot be instantiated from " + pre.widen());
} else {
- return toInstance(
- pre.baseType(clazz).prefix(), clazz.owner());
+ return toInstance(sym, pre.baseType(clazz).prefix(), clazz.owner());
}
}
- Type toPrefix(Type pre, Symbol clazz) {
+ Type toPrefix(Symbol sym, Type pre, Symbol clazz) {
if (pre == NoType || clazz.kind != CLASS)
return this;
- else if (symbol().isSubClass(clazz) &&
- pre.widen().symbol().isSubClass(symbol()))
+ else if (sym.isSubClass(clazz) &&
+ pre.widen().symbol().isSubClass(sym))
return pre;
else
- return toPrefix(pre.baseType(clazz).prefix(), clazz.owner());
+ return toPrefix(sym, pre.baseType(clazz).prefix(), clazz.owner());
}
- /** This type Types as seen from prefix `pre' and class `clazz'. This means:
- * Replace all this thistypes of `clazz' or one of its superclasses by `pre'.
+ /** This type as seen from prefix `pre' and class `clazz'. This means:
+ * Replace all thistypes of `clazz' or one of its superclasses by `pre'
+ * and instantiate all parameters by arguments of `pre'.
* Proceed analogously for thistypes referring to outer classes.
*/
public Type asSeenFrom(Type pre, Symbol clazz) {
@@ -939,21 +903,17 @@ public class Type implements Modifiers, Kinds, TypeTags {
/** The info of `sym', seen as a member of this type.
*/
public Type memberInfo(Symbol sym) {
- return memberTransform(sym, sym.info());
+ return sym.info().asSeenFrom(this, sym.owner());
}
/** The type of `sym', seen as a member of this type.
*/
public Type memberType(Symbol sym) {
- return memberTransform(sym, sym.type());
- }
-
- private Type memberTransform(Symbol sym, Type tp) {
- Type tp1 = tp.asSeenFrom(this, sym.owner());
- //if (Global.instance.debug) System.out.println(this + ".memberType(" + sym + ":" + tp + ") = " + tp1);//DEBUG
- return tp1;
+ return sym.type().asSeenFrom(this, sym.owner());
}
+ /** The low bound of `sym', seen as a member of this type.
+ */
public Type memberLoBound(Symbol sym) {
return sym.loBound().asSeenFrom(this, sym.owner());
}
@@ -1167,17 +1127,19 @@ public class Type implements Modifiers, Kinds, TypeTags {
this.sym = sym;
}
public Type apply(Type t) {
- switch (t) {
- case TypeRef(Type pre, Symbol sym1, Type[] args):
- if (sym == sym1) result = true;
- else { map(pre); map(args); }
- break;
- case SingleType(Type pre, Symbol sym1):
- map(pre);
- if (sym == sym1) result = true;
- break;
- default:
- map(t);
+ if (!result) {
+ switch (t) {
+ case TypeRef(Type pre, Symbol sym1, Type[] args):
+ if (sym == sym1) result = true;
+ else { map(pre); map(args); }
+ break;
+ case SingleType(Type pre, Symbol sym1):
+ map(pre);
+ if (sym == sym1) result = true;
+ break;
+ default:
+ map(t);
+ }
}
return t;
}
@@ -1276,7 +1238,8 @@ public class Type implements Modifiers, Kinds, TypeTags {
Symbol p1 = ps1[i];
Symbol p = ps[i];
if (!p1.type().isSubType(p.type()) ||
- (p1.flags & Modifiers.DEF) != (p.flags & Modifiers.DEF))
+ (p1.flags & (Modifiers.DEF | Modifiers.REPEATED)) !=
+ (p.flags & (Modifiers.DEF | Modifiers.REPEATED)))
return false;
}
return res.isSubType(res1);
@@ -1288,15 +1251,18 @@ public class Type implements Modifiers, Kinds, TypeTags {
case PolyType(Symbol[] ps, Type res):
if (ps.length != ps1.length) return false;
for (int i = 0; i < ps.length; i++)
- if (!ps1[i].info().subst(ps1, ps).isSubType(ps[i].info()))
+ if (!ps1[i].info().subst(ps1, ps).isSubType(ps[i].info()) ||
+ !ps[i].loBound().isSubType(ps1[i].loBound().subst(ps1, ps)))
return false;
return res.isSubType(res1.subst(ps1, ps));
}
break;
case OverloadedType(Symbol[] alts1, Type[] alttypes1):
- if (isSubSet(alttypes1, alternatives()))
- return true;
+ for (int i = 0; i < alttypes1.length; i++) {
+ if (!isSubType(alttypes1[i]))
+ return false;
+ }
break;
case UnboxedType(int tag1):
@@ -1339,7 +1305,7 @@ public class Type implements Modifiers, Kinds, TypeTags {
return false;
case ThisType(_):
case SingleType(_, _):
- if (this.widen().isSubType(that)) return true;
+ if (this.singleDeref().isSubType(that)) return true;
break;
case TypeVar(Type origin, Constraint constr):
if (constr.inst != NoType) {
@@ -1367,7 +1333,7 @@ public class Type implements Modifiers, Kinds, TypeTags {
case OverloadedType(Symbol[] alts, Type[] alttypes):
for (int i = 0; i < alttypes.length; i++) {
- if (alttypes[i].isSameAs0(that)) return true;
+ if (alttypes[i].isSubType(that)) return true;
}
break;
}
@@ -1444,11 +1410,17 @@ public class Type implements Modifiers, Kinds, TypeTags {
public boolean specializes0(Symbol sym1) {
Symbol sym = lookup(sym1.name);
Type self = narrow();
+ Symbol[] tparams = symbol().typeParams();
+ Type[] targs = typeArgs();
return
- sym == sym1 ||
- ((sym.kind == sym1.kind || sym1.kind == TYPE) &&
- self.memberInfo(sym).subst(symbol().typeParams(), typeArgs())
- .isSubType(sym1.info().substThis(sym.owner(), self))) ||
+ sym == sym1
+ ||
+ (sym.kind == sym1.kind || sym1.kind == TYPE) &&
+ self.memberInfo(sym).subst(tparams, targs)
+ .isSubType(sym1.info().substThis(sym.owner(), self)) &&
+ sym1.loBound().substThis(sym.owner(), self)
+ .isSubType(self.memberLoBound(sym).subst(tparams, targs))
+ ||
(sym.kind == TYPE && sym1.kind == ALIAS &&
sym1.info().unalias().isSameAs(sym.type()));
}
@@ -1487,8 +1459,8 @@ public class Type implements Modifiers, Kinds, TypeTags {
&& sym == sym1.moduleClass()
&& sym.owner().thisType().isSameAs(pre1)
||
- that != that.aliasedType() &&
- this.isSameAs(that.aliasedType());
+ deAlias(that) != that &&
+ this.isSameAs(deAlias(that));
}
break;
@@ -1497,15 +1469,15 @@ public class Type implements Modifiers, Kinds, TypeTags {
case SingleType(Type pre1, Symbol sym1):
return sym == sym1 && pre.isSameAs(pre1)
||
- (this != this.aliasedType() || that != that.aliasedType()) &&
- this.aliasedType().isSameAs(that.aliasedType());
+ (deAlias(this) != this || deAlias(that) != that) &&
+ deAlias(this).isSameAs(deAlias(that));
case ThisType(Symbol sym1):
return sym.isModule()
&& sym.moduleClass() == sym1
&& pre.isSameAs(sym1.owner().thisType())
||
- this != this.aliasedType() &&
- this.aliasedType().isSameAs(that);
+ deAlias(this) != this &&
+ deAlias(this).isSameAs(that);
}
break;
@@ -1535,7 +1507,8 @@ public class Type implements Modifiers, Kinds, TypeTags {
Symbol p1 = ps1[i];
Symbol p = ps[i];
if (!p1.type().isSameAs(p.type()) ||
- (p1.flags & Modifiers.DEF) != (p.flags & Modifiers.DEF))
+ (p1.flags & (Modifiers.DEF | Modifiers.REPEATED)) !=
+ (p.flags & (Modifiers.DEF | Modifiers.REPEATED)))
return false;
}
return res.isSameAs(res1);
@@ -1547,7 +1520,8 @@ public class Type implements Modifiers, Kinds, TypeTags {
case PolyType(Symbol[] ps1, Type res1):
if (ps.length != ps1.length) return false;
for (int i = 0; i < ps.length; i++)
- if (!ps1[i].info().subst(ps1, ps).isSameAs(ps[i].info()))
+ if (!ps1[i].info().subst(ps1, ps).isSameAs(ps[i].info()) ||
+ !ps1[i].loBound().subst(ps1, ps).isSameAs(ps[i].loBound()))
return false;
return res.isSameAs(res1.subst(ps1, ps));
}
@@ -1605,6 +1579,15 @@ public class Type implements Modifiers, Kinds, TypeTags {
return false;
}
+ //where
+ Type deAlias(Type tp) {
+ switch (tp) {
+ case SingleType(_, _):
+ Type tp1 = tp.singleDeref();
+ if (tp1.isStable()) return deAlias(tp1);
+ }
+ return tp;
+ }
/** Are types `these' the same as corresponding types `those'?
*/
@@ -1630,7 +1613,11 @@ public class Type implements Modifiers, Kinds, TypeTags {
Symbol sym1 = s1.lookup(sym2.name);
if (sym1.kind != sym2.kind ||
!sym1.info().isSameAs(
- sym2.info().substThis(sym2.owner(), sym1.owner().thisType())))
+ sym2.info().substThis(
+ sym2.owner(), sym1.owner().thisType())) ||
+ !sym1.loBound().isSameAs(
+ sym2.loBound().substThis(
+ sym2.owner(), sym1.owner().thisType())))
return false;
}
return true;
@@ -1661,8 +1648,6 @@ public class Type implements Modifiers, Kinds, TypeTags {
/** The closure of this type, i.e. the widened type itself followed by all
* its direct and indirect (pre-) base types, sorted by Symbol.isLess().
- * Note that (pre-) base types do _not_ carry type parameters; these
- * are added by baseType().
*/
public Type[] closure() {
switch (this.widen().unalias()) {
@@ -1682,7 +1667,9 @@ public class Type implements Modifiers, Kinds, TypeTags {
}
}
- /** return union of array of closures
+ /** return union of array of closures. It is assumed that
+ * for any two base types with the same class symbols the later one
+ * is a subtype of the former.
*/
static private Type[] union(Type[][] closures) {
if (closures.length == 1) return closures[0]; // fast special case
@@ -1703,7 +1690,7 @@ public class Type implements Modifiers, Kinds, TypeTags {
Type cltype = closures[i][index[i]];
if (min == null ||
cltype.symbol().isLess(min.symbol()) ||
- cltype.symbol() == min.symbol() && cltype.isSubType(min)) {
+ cltype.symbol() == min.symbol()) {
min = cltype;
}
}
@@ -1725,7 +1712,7 @@ public class Type implements Modifiers, Kinds, TypeTags {
return result;
}
- /** return intersection of array of closures
+ /** return intersection of non-empty array of closures
*/
static private Type[] intersection(Type[][] closures) {
if (closures.length == 1) return closures[0]; // fast special case
@@ -1742,18 +1729,18 @@ public class Type implements Modifiers, Kinds, TypeTags {
L:
while (true) {
// find minimal element
- Symbol min = null;
+ Symbol minsym = null;
for (int i = 0; i < index.length; i++) {
if (index[i] == closures[i].length) break L;
Symbol clsym = closures[i][index[i]].symbol();
- if (min == null || clsym.isLess(min)) min = clsym;
+ if (minsym == null || clsym.isLess(minsym)) minsym = clsym;
}
boolean agree = true;
// bump all indices that start with minimal element
for (int i = 0; i < index.length; i++) {
Type cltype = closures[i][index[i]];
- if (cltype.symbol() == min) {
+ if (cltype.symbol() == minsym) {
mintypes[i] = cltype;
index[i] = index[i] + 1;
} else {
@@ -1761,10 +1748,7 @@ public class Type implements Modifiers, Kinds, TypeTags {
}
}
if (agree) {
- Type mintype;
- mintype = commonType(mintypes);
- if (mintype == NoType)
- mintype = arglub(mintypes);
+ Type mintype = argLub(mintypes);
if (mintype.symbol().kind == CLASS) {
res[j] = mintype;
j = j + 1;
@@ -1780,14 +1764,17 @@ public class Type implements Modifiers, Kinds, TypeTags {
* possibly with different prefixes and arguments.
*/
//todo: catch lubs not within bounds.
- static Type arglub(Type[] types) {
- Type pre = types[0].prefix();
- Symbol sym = types[0].symbol();
+ static Type argLub(Type[] tps) {
+ tps = elimRedundant(tps, true);
+ if (tps.length == 1) return tps[0];
+
+ Type pre = tps[0].prefix();
+ Symbol sym = tps[0].symbol();
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]) {
+ Type[][] argss = new Type[args.length][tps.length];
+ for (int i = 0; i < tps.length; i++) {
+ switch (tps[i]) {
case TypeRef(Type pre1, Symbol sym1, Type[] args1):
assert sym == sym1;
assert args1.length == args.length;
@@ -1798,18 +1785,15 @@ public class Type implements Modifiers, Kinds, TypeTags {
case ErrorType:
return ErrorType;
default:
- assert false : types[i];
+ assert false : tps[i];
}
}
for (int j = 0; j < args.length; j++) {
- args[j] = commonType(argss[j]);
- if (args[j] == NoType) {
- if ((tparams[j].flags & COVARIANT) != 0)
- args[j] = lub(argss[j]);
- else if ((tparams[j].flags & CONTRAVARIANT) != 0)
- args[j] = glb(argss[j]);
- else return NoType;
- }
+ if ((tparams[j].flags & COVARIANT) != 0)
+ args[j] = lub(argss[j]);
+ else if ((tparams[j].flags & CONTRAVARIANT) != 0)
+ args[j] = glb(argss[j]);
+ else return NoType;
}
return typeRef(pre, sym, args);
}
@@ -1877,8 +1861,9 @@ public class Type implements Modifiers, Kinds, TypeTags {
public static Type lub(Type[] tps) {
//System.out.println("lub" + ArrayApply.toString(tps));//DEBUG
- // remove types that are subtypes of some other type.
+ if (tps.length == 0) return Global.instance.definitions.ALL_TYPE;
+ // remove types that are subtypes of some other type.
tps = elimRedundant(tps, true);
if (tps.length == 1) return tps[0];
@@ -1889,10 +1874,7 @@ public class Type implements Modifiers, Kinds, TypeTags {
}
Type[] allBaseTypes = intersection(closures);
Type[] leastBaseTypes = frontier(allBaseTypes);
- if (leastBaseTypes.length == 0) {
- //System.out.println("empty intersection");//DEBUG
- return Type.NoType;
- }
+ assert leastBaseTypes.length > 0 : ArrayApply.toString(tps);
// add refinements where necessary
Scope members = new Scope();
@@ -1909,14 +1891,14 @@ public class Type implements Modifiers, Kinds, TypeTags {
e = e.next) {
Name name = e.sym.name;
if ((e.sym.flags & PRIVATE) == 0 && lubType.lookup(name) == e.sym) {
- //todo: not memberType?
- Type symType = lubThisType.memberInfo(e.sym);
+ //todo: not info?
+ Type symType = memberTp(lubThisType, e.sym);
Type symLoBound = lubThisType.memberLoBound(e.sym);
int j = 0;
while (j < tps.length) {
rsyms[j] = tps[j].lookupNonPrivate(name);
if (rsyms[j] == e.sym) break;
- rtps[j] = tps[j].memberType(rsyms[j])
+ rtps[j] = memberTp(tps[j], rsyms[j])
.substThis(tps[j].symbol(), lubThisType);
rlbs[j] = tps[j].memberLoBound(rsyms[j])
.substThis(tps[j].symbol(), lubThisType);
@@ -1926,7 +1908,10 @@ public class Type implements Modifiers, Kinds, TypeTags {
}
if (j == tps.length) {
Symbol lubSym = lub(rsyms, rtps, rlbs, lubType.symbol());
- if (lubSym.kind != NONE && !lubSym.info().isSameAs(symType))
+ if (lubSym.kind != NONE &&
+ !(lubSym.kind == e.sym.kind &&
+ lubSym.info().isSameAs(symType) &&
+ lubSym.loBound().isSameAs(symType)))
members.enter(lubSym);
}
}
@@ -1937,12 +1922,10 @@ public class Type implements Modifiers, Kinds, TypeTags {
return leastBaseTypes[0];
else return lubType;
}
-
- private static Type commonType(Type[] tps) {
- Type tp = tps[0];
- if (tp.isSameAsAll(tps)) return tp;
- else return NoType;
- }
+ //where
+ private static Type memberTp(Type base, Symbol sym) {
+ return sym.kind == CLASS ? base.memberType(sym) : base.memberInfo(sym);
+ }
private static Symbol lub(Symbol[] syms, Type[] tps, Type[] lbs, Symbol owner) {
//System.out.println("lub" + ArrayApply.toString(syms));//DEBUG
@@ -1955,6 +1938,7 @@ public class Type implements Modifiers, Kinds, TypeTags {
if (lubKind == syms[0].kind && tps[0].isSameAsAll(tps)) {
return syms[0].cloneSymbol();
}
+
Type lubType = lub(tps);
if (lubType == Type.NoType) return Symbol.NONE;
Symbol lubSym;
@@ -1973,7 +1957,9 @@ public class Type implements Modifiers, Kinds, TypeTags {
return lubSym;
}
- private static Type glb(Type[] tps) {
+ public static Type glb(Type[] tps) {
+ if (tps.length == 0) return Global.instance.definitions.ANY_TYPE;
+
// step one: eliminate redunandant types; return if one one is left
tps = elimRedundant(tps, false);
if (tps.length == 1) return tps[0];
@@ -2048,7 +2034,7 @@ public class Type implements Modifiers, Kinds, TypeTags {
i++) {
for (int j = 0; j < i; j++) {
if (treftypes[j].symbol() == treftypes[i].symbol())
- lb = argglb(treftypes[j], treftypes[i]);
+ lb = argGlb(treftypes[j], treftypes[i]);
}
}
if (lb != NoType) return lb;
@@ -2062,7 +2048,7 @@ public class Type implements Modifiers, Kinds, TypeTags {
}
}
- private static Type argglb(Type tp1, Type tp2) {
+ private static Type argGlb(Type tp1, Type tp2) {
switch (tp1) {
case TypeRef(Type pre1, Symbol sym1, Type[] args1):
switch (tp2) {
@@ -2079,15 +2065,17 @@ public class Type implements Modifiers, Kinds, TypeTags {
else if ((tparams[i].flags & CONTRAVARIANT) != 0)
args[i]= glb(new Type[]{args1[i], args2[i]});
else
- return tp1.loBound();
+ return glb(new Type[]{tp1.loBound(), tp2.loBound()});
}
return typeRef(pre1, sym1, args);
}
}
}
- return tp1.loBound();
+ return glb(new Type[]{tp1.loBound(), tp2.loBound()});
}
+ /** Set scope `result' to glb of scopes `ss'. Return true iff succeeded.
+ */
private static boolean setGlb(Scope result, Scope[] ss, Type glbThisType) {
for (int i = 0; i < ss.length; i++)
for (Scope.Entry e = ss[i].elems; e != Scope.Entry.NONE; e = e.next)
@@ -2095,6 +2083,9 @@ public class Type implements Modifiers, Kinds, TypeTags {
return true;
}
+ /** Add member `sym' to scope `s'. If`s' has already a member with same name,
+ * overwrite its info/low bound to form glb of both symbols.
+ */
private static boolean addMember(Scope s, Symbol sym, Type glbThisType) {
Type syminfo = sym.info().substThis(sym.owner(), glbThisType);
Type symlb = sym.loBound().substThis(sym.owner(), glbThisType);
@@ -2206,9 +2197,9 @@ public class Type implements Modifiers, Kinds, TypeTags {
case TypeRef(Type pre, Symbol sym, Type[] args):
if ((sym.flags & MODUL) == 0) {
Name fullname = sym.fullName();
- if (fullname == Names.scala_Array && args.length == 1
- /*&& args[0].unalias().symbol().kind != TYPE Q: why needed?*/) {
- Type bound = args[0].bound();
+ if (fullname == Names.scala_Array && args.length == 1) {
+ Type bound = upperBound(args[0]);
+ // todo: check with Philippe if this is what we want.
if (bound.symbol() != Global.instance.definitions.ANY_CLASS &&
bound.symbol() != Global.instance.definitions.ANYVAL_CLASS)
{
@@ -2222,6 +2213,15 @@ public class Type implements Modifiers, Kinds, TypeTags {
}
return this;
}
+ //where
+ private Type upperBound(Type tp) {
+ switch (tp) {
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ if (sym.kind == ALIAS || sym.kind == TYPE)
+ return upperBound(pre.memberInfo(sym));
+ }
+ return tp;
+ }
/** Return the erasure of this type.
*/
@@ -2229,7 +2229,7 @@ public class Type implements Modifiers, Kinds, TypeTags {
switch (this) {
case ThisType(_):
case SingleType(_, _):
- return widen().erasure();
+ return singleDeref().erasure();
case TypeRef(Type pre, Symbol sym, Type[] args):
switch (sym.kind) {
case ALIAS: case TYPE:
diff --git a/sources/scalac/typechecker/Analyzer.java b/sources/scalac/typechecker/Analyzer.java
index 6964ec8644..dbe7a6122b 100644
--- a/sources/scalac/typechecker/Analyzer.java
+++ b/sources/scalac/typechecker/Analyzer.java
@@ -277,6 +277,9 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
if ((sym.flags & DEF) != 0 && sym.owner().isPrimaryConstructor()) {
error(sym.pos, "`def' modifier not allowed for class parameters");
}
+ if ((sym.flags & REPEATED) != 0 && sym.owner().isPrimaryConstructor()) {
+ error(sym.pos, "`*' modifier not allowed for class parameters");
+ }
if ((sym.flags & DEFERRED) != 0) {
if (sym.owner().kind != CLASS ||
(sym.owner().flags & MODUL) != 0 ||
diff --git a/sources/scalac/typechecker/Infer.java b/sources/scalac/typechecker/Infer.java
index c060ca8067..b3cd5436df 100644
--- a/sources/scalac/typechecker/Infer.java
+++ b/sources/scalac/typechecker/Infer.java
@@ -189,17 +189,19 @@ public class Infer implements Modifiers, Kinds {
}
/** Map type variable to its instance, or, if `covariant' is true,
- * to its upper bound (if this is not AnyType);
- * or return `AnyType' if not possible.
+ * to its upper bound;
*/
- private Type instantiateUpper(Type tp, boolean covariant) throws NoInstance {
+ private Type instantiateUpper(Type tp, boolean covariant) {
switch (tp) {
case TypeVar(Type origin, Type.Constraint constr):
- if (constr.inst != Type.NoType) {
- return instantiate(constr.inst);
- } else if (covariant && constr.hibounds != Type.List.EMPTY) {
- maximizeVar(tp);
- return instantiate(constr.inst);
+ try {
+ if (constr.inst != Type.NoType) {
+ return instantiate(constr.inst);
+ } else if (covariant && constr.hibounds != Type.List.EMPTY) {
+ maximizeVar(tp);
+ return instantiate(constr.inst);
+ }
+ } catch (NoInstance ex) {
}
return Type.AnyType;
default:
@@ -207,6 +209,23 @@ public class Infer implements Modifiers, Kinds {
}
}
+ /** The formal parameter types corresponding to `params'.
+ * If `params' is a repeated parameter, a list of `length' copies
+ * of its type is returned.
+ */
+ public Type[] formalTypes(Symbol[] params, int length) {
+ Type[] result;
+ if (params.length == 1 && (params[0].flags & REPEATED) != 0) {
+ Type[] formals = new Type[length];
+ Type ft = params[0].type().typeArgs()[0];
+ // params[0] has type Seq[T], we need T here
+ for (int i = 0; i < length; i++) formals[i] = ft;
+ return formals;
+ } else {
+ return Symbol.type(params);
+ }
+ }
+
/** Is type fully defined, i.e. no embedded anytypes or typevars in it?
*/
public boolean isFullyDefined(Type tp) {
@@ -221,9 +240,9 @@ public class Infer implements Modifiers, Kinds {
/** Do type arguments `targs' conform to formal parameters `tparams'?
*/
private boolean isWithinBounds(Symbol[] tparams, Type[] targs) {
- // check that covariant types do not appear in F-bounds.
for (int i = 0; i < targs.length; i++) {
- if (!targs[i].isSubType(tparams[i].info().subst(tparams, targs)))
+ if (!targs[i].isSubType(tparams[i].info().subst(tparams, targs)) ||
+ !tparams[i].loBound().subst(tparams, targs).isSubType(targs[i]))
return false;
}
return true;
@@ -241,76 +260,27 @@ public class Infer implements Modifiers, Kinds {
}
}
- /** Instantiate undetermined variable to its minimal upper bound.
- * Throw a NoInstance exception if this not possible.
+ /** Instantiate variable to glb of its high bounds.
*/
- private void maximizeVar(Type tp) throws NoInstance {
+ private void maximizeVar(Type tp) {
switch (tp) {
case TypeVar(Type origin, Type.Constraint constr):
- if (constr.inst == Type.NoType) {
- if (constr.hibounds == Type.List.EMPTY)
- constr.inst = definitions.ANY_TYPE;
- else if (constr.hibounds.tail == Type.List.EMPTY)
- constr.inst = constr.hibounds.head;
- else {
- for (Type.List bs = constr.hibounds;
- bs != Type.List.EMPTY && constr.inst == Type.NoType;
- bs = bs.tail) {
- //System.out.println("hibound: " + bs.head);//DEBUG
- if (isSubSymOfAll(bs.head, constr.hibounds)) {
- //System.out.println("best: " + bs.head);//DEBUG
- constr.inst = bs.head.any2typevar();
- }
- }
- }
- if (constr.inst == Type.NoType ||
- !isSubTypeOfAll(constr.inst, constr.hibounds)) {
- throw new NoInstance(
- "no unique maximal instance exists for type variable " +
- origin);
- }
- }
- return;
+ if (constr.inst == Type.NoType)
+ constr.inst = Type.glb(constr.hibounds.toArray());
+ break;
default:
throw new ApplicationError();
}
}
- //where
- private boolean isSubSymOfAll(Type tp, Type.List tps) {
- Symbol sym = tp.unalias().symbol();
- for (Type.List l = tps; l != Type.List.EMPTY; l = l.tail) {
- if (!isSubSym(sym, l.head.unalias().symbol())) return false;
- }
- return true;
- }
-
- private boolean isSubSym(Symbol sym, Symbol sym1) {
- return
- sym == sym1 ||
- sym.kind == ERROR ||
- (sym.kind == TYPE || sym.kind == CLASS) && sym.isSubClass(sym1);
- }
-
- private boolean isSubTypeOfAll(Type tp, Type.List tps) {
- for (Type.List l = tps; l != Type.List.EMPTY; l = l.tail) {
- if (!tp.isSubType(l.head)) return false;
- }
- return true;
- }
+ /** Instantiate variable to lub of its low bounds.
+ */
private void minimizeVar(Type tp) {
switch (tp) {
case TypeVar(Type origin, Type.Constraint constr):
if (constr.inst == Type.NoType)
- if (constr.lobounds != Type.List.EMPTY) {
- //System.out.println("LOBOUNDS = " + constr.lobounds);//DEBUG
- constr.inst = Type.lub(constr.lobounds.toArray());
- //System.out.println("MIN = " + constr.inst);//DEBUG
-
- } else {
- constr.inst = global.definitions.ALL_TYPE;
- }
- return;
+ constr.inst = Type.lub(constr.lobounds.toArray());
+ break;
default:
throw new ApplicationError();
}
@@ -349,7 +319,6 @@ public class Infer implements Modifiers, Kinds {
maximizeVar(tvar);
tvars[i] = ((Type.TypeVar) tvar).constr.inst;
}
- if (tvars[i] == Type.AnyType) tvars[i] = definitions.ANY_TYPE;
}
}
}
@@ -386,15 +355,6 @@ public class Infer implements Modifiers, Kinds {
}
}
}
- for (int j = 0; j < tvars.length; j++) {
- if (bound.contains(tparams[j]) ||
- tparams[j].info().isSameAs(tparams[i].type())) {
- cyclic |= tvars[j] == Type.NoType;
- solveLower(tparams, tvars, j);
- }
- }
-
-
}
minimizeVar(tvar);
tvars[i] = ((Type.TypeVar) tvar).constr.inst;
@@ -421,6 +381,10 @@ public class Infer implements Modifiers, Kinds {
Symbol[] newparams1 = Symbol.EMPTY_ARRAY;
switch (restp1) {
case PolyType(_, _):
+ // If there is a nested polytype, we need to
+ // substitute also its new type parameters for its old ones
+ // here. Reason: The outer polytype may refer to type
+ // variables of the inner one.
tparams1 = restp.typeParams();
newparams1 = restp1.typeParams();
}
@@ -456,21 +420,27 @@ public class Infer implements Modifiers, Kinds {
* A method type becomes the corresponding function type.
* A nullary method type becomes its result type.
*/
- private Type normalize(Type tp, Type pt) {
+ private Type normalize(Type tp) {
switch (tp) {
case MethodType(Symbol[] params, Type restype):
return global.definitions.functionType(
- Symbol.type(params), normalize(restype, Type.AnyType));
+ Symbol.type(params), normalize(restype));
case PolyType(Symbol[] tparams, Type restype):
- if (tparams.length == 0) return normalize(restype, pt);
+ if (tparams.length == 0) return normalize(restype);
}
return tp;
}
+ /** Is normalized type `tp' a subtype of prototype `pt'?
+ */
boolean isCompatible(Type tp, Type pt) {
- return normalize(tp, pt).isSubType(pt);
+ return normalize(tp).isSubType(pt);
}
+ /** Type arguments mapped to `scala.All' are taken to be uninstantiated.
+ * Map all those type arguments to their corresponding type parameters
+ * and return all these type parameters as result.
+ */
private Symbol[] normalizeArgs(Type[] targs, Symbol[] tparams) {
Type.List uninstantiated = Type.List.EMPTY;
for (int i = 0; i < targs.length; i++) {
@@ -484,24 +454,14 @@ public class Infer implements Modifiers, Kinds {
/** Return inferred type arguments of polymorphic expression, given
* its type parameters and result type and a prototype `pt'.
- * If no maximal type variables exists that make the
- * instantiated type a subtype of `pt' and `lastTry' is true, return `null'.
+ * If no minimal type variables exist that make the
+ * instantiated type a subtype of `pt', return `null'.
*/
private Type[] exprTypeArgs(Symbol[] tparams, Type restype, Type pt) {
Type[] tvars = freshVars(tparams);
- // add all bounds except F-bounds to upper bounds of type variable.
- for (int i = 0; i < tvars.length; i++) {
- switch (tvars[i]) {
- case TypeVar(_, Type.Constraint constr):
- Type bound = tparams[i].info();
- if (!bound.containsSome(tparams))
- constr.hibounds = new Type.List(bound, Type.List.EMPTY);
- }
- }
Type insttype = restype.subst(tparams, tvars);
if (isCompatible(insttype, pt)) {
try {
- Type[] targs = new Type[tvars.length];
for (int i = 0; i < tvars.length; i++) {
solveLower(tparams, tvars, i);
}
@@ -512,64 +472,80 @@ public class Infer implements Modifiers, Kinds {
return null;
}
- /** As before, but: don't minimize. Instead map all unistantiated
- * type vars to AnyType.
+ /** Return inferred proto-type arguments of function, given
+ * its type and value parameters and result type, and a
+ * prototype `pt' for the function result.
+ * Type arguments need to be either determined precisely by
+ * the prototype, or they are maximized, if they occur only covariantly
+ * in the value parameter list.
+ * If instantiation of a type parameter fails,
+ * take Type.AnyType for the proto-type argument.
*/
public Type[] protoTypeArgs(Symbol[] tparams, Type restype, Type pt,
Symbol[] params) {
Type[] tvars = freshVars(tparams);
Type insttype = restype.subst(tparams, tvars);
Type[] targs = new Type[tvars.length];
+ for (int i = 0; i < tvars.length; i++) targs[i] = Type.AnyType;
if (isCompatible(insttype, pt)) {
try {
for (int i = 0; i < tvars.length; i++) {
- targs[i] = instantiateUpper(tvars[i], isCovariant(tparams[i], params));
+ targs[i] = instantiateUpper(
+ tvars[i], isVariant(tparams[i], params, 1));
}
return targs;
} catch (NoInstance ex) {
}
}
- for (int i = 0; i < tvars.length; i++) {
- targs[i] = Type.AnyType;
- }
return targs;
}
- /** Does given `tparam' occur only covariantly in symbols?
+ /** Does given `tparam' occur with variance `v' in symbols?
*/
- private boolean isCovariant(Symbol tparam, Symbol[] syms) {
+ private boolean isVariant(Symbol tparam, Symbol[] syms, int v) {
for (int i = 0; i < syms.length; i++) {
- if (!isCovariant(tparam, syms[i])) return false;
+ if (!isVariant(tparam, syms[i], v)) return false;
}
return true;
}
- /** Does given `tparam' occur only covariantly in symbol?
+ /** Does given `tparam' occur with variance `v' in symbol?
*/
- private boolean isCovariant(Symbol tparam, Symbol sym) {
+ private boolean isVariant(Symbol tparam, Symbol sym, int v) {
switch (sym.kind) {
- case ERROR: case VAL: case TYPE: return isCovariant(tparam, sym.info());
- case ALIAS: return !sym.info().contains(tparam);
- default: return false;
+ case ERROR:
+ return true;
+ case VAL:
+ return isVariant(tparam, sym.info(), v);
+ case TYPE:
+ return isVariant(tparam, sym.info(), v) &&
+ isVariant(tparam, sym.loBound(), -v);
+ case ALIAS:
+ return !sym.info().contains(tparam);
+ default:
+ return false;
}
}
- /** Does given `tparam' occur only covariantly in types?
+ /** Does given `tparam' occur with variance `v' in types?
*/
- private boolean isCovariant(Symbol tparam, Type[] tps) {
+ private boolean isVariant(Symbol tparam, Type[] tps, int v) {
for (int i = 0; i < tps.length; i++) {
- if (!isCovariant(tparam, tps[i])) return false;
+ if (!isVariant(tparam, tps[i], v)) return false;
}
return true;
}
- /** Does given `tvar' occur only covariantly in argument types `tps' for formal
- * type parameetrs `tparams'?
+ /** Does given `tparam' occur with variance `v' in argument types `tps'
+ * which correspond to formal type parameters `tparams'?
*/
- private boolean isCovariantArgs(Symbol tvar, Type[] tps, Symbol[] tparams) {
+ private boolean isVariantArgs(Symbol tvar, Type[] tps, Symbol[] tparams,
+ int v) {
for (int i = 0; i < tps.length; i++) {
if ((tparams[i].flags & COVARIANT) != 0) {
- if (!isCovariant(tvar, tps[i])) return false;
+ if (!isVariant(tvar, tps[i], v)) return false;
+ } else if ((tparams[i].flags & CONTRAVARIANT) != 0) {
+ if (!isVariant(tvar, tps[i], -v)) return false;
} else {
if (tps[i].contains(tvar)) return false;
}
@@ -577,9 +553,9 @@ public class Infer implements Modifiers, Kinds {
return true;
}
- /** Does given `tparam' occur only covariantly in type?
+ /** Does given `tparam' occur with variance `v' in type?
*/
- private boolean isCovariant(Symbol tparam, Type tp) {
+ private boolean isVariant(Symbol tparam, Type tp, int v) {
switch (tp) {
case ErrorType:
case AnyType:
@@ -587,33 +563,18 @@ public class Infer implements Modifiers, Kinds {
case ThisType(Symbol sym):
return true;
case TypeRef(Type pre, Symbol sym, Type[] args):
- return isCovariant(tparam, pre) && isCovariantArgs(tparam, args, sym.typeParams());
+ return isVariant(tparam, pre, v) &&
+ isVariantArgs(tparam, args, sym.typeParams(), v);
case SingleType(Type pre, Symbol sym):
return !pre.contains(tparam);
case CompoundType(Type[] parts, Scope members):
- return isCovariant(tparam, parts) &&
- isCovariant(tparam, members.elements());
+ return isVariant(tparam, parts, v) &&
+ isVariant(tparam, members.elements(), v);
default:
throw new ApplicationError();
}
}
- /** The formal parameter types corresponding to `params'.
- * If `params' is a repeated parameter, a list of `length' copies
- * of its type is returned.
- */
- Type[] formalTypes(Symbol[] params, int length) {
- Type[] result;
- if (params.length == 1 && (params[0].flags & REPEATED) != 0) {
- Type[] formals = new Type[length];
- Type ft = params[0].type().typeArgs()[0];
- for (int i = 0; i < length; i++) formals[i] = ft;
- return formals;
- } else {
- return Symbol.type(params);
- }
- }
-
/** Return inferred type arguments, given type parameters, formal parameters,
* argument types, result type and expected result type.
* If this is not possible, throw a `NoInstance' exception, or, if
@@ -650,23 +611,22 @@ public class Infer implements Modifiers, Kinds {
// Then define remaining type variables from argument types.
for (int i = 0; i < argtypes.length; i++) {
- if (!isCompatible(argtypes[i].subst(tparams, tvars),
+ if (!isCompatible(argtypes[i].widen().subst(tparams, tvars),
formals[i].subst(tparams, tvars))) {
if (needToSucceed) {
- Type.debugSwitch = true;
- argtypes[i].subst(tparams, tvars).isSubType(
- formals[i].subst(tparams, tvars));
- Type.debugSwitch = false;
+ if (Type.debugSwitch) {
+ argtypes[i].widen().subst(tparams, tvars).isSubType(
+ formals[i].subst(tparams, tvars));
+ }
throw new NoInstance(
typeErrorMsg(
"argument expression's type is not compatible with formal parameter type",
- argtypes[i].subst(tparams, tvars),
+ argtypes[i].widen().subst(tparams, tvars),
formals[i].subst(tparams, tvars)));
}
return null;
}
}
- Type[] targs = new Type[tvars.length];
for (int i = 0; i < tvars.length; i++) {
solveLower(tparams, tvars, i);
}
@@ -705,11 +665,11 @@ public class Infer implements Modifiers, Kinds {
}
/** Return the instantiated and normalized type of polymorphic expression
- * with type `[tparams]restype', given a two prototypes `pt1', and `pt2'.
+ * with type `[tparams]restype', given two prototypes `pt1', and `pt2'.
* `pt1' is the strict first attempt prototype where type parameters
* are left unchanged. `pt2' is the fall-back prototype where type parameters
* are replaced by `AnyType's. We try to instantiate first to `pt1' and then,
- * if this fails, to `pt2'. If both atempts fail, a `Type.Error' is thrown.
+ * if this fails, to `pt2'. If both attempts fail, a Type.Error is thrown.
*/
Type argumentTypeInstance(Symbol[] tparams, Type restype, Type pt1, Type pt2)
throws Type.Error {
@@ -732,13 +692,13 @@ public class Infer implements Modifiers, Kinds {
checkBounds(tparams, targs, "inferred ");
return restype.subst(tparams, targs);
} else {
- return normalize(restype, pt2);
+ return normalize(restype);
}
}
}
- /** Instantiate expression `tree' of polymorphic type with given `tparams' and
- * `restype', using prototype `pt'.
+ /** Instantiate expression `tree' of polymorphic type [tparams]restype,
+ * using prototype `pt'.
*/
public Tree exprInstance(Tree tree, Symbol[] tparams, Type restype, Type pt)
throws Type.Error {
@@ -758,12 +718,13 @@ public class Infer implements Modifiers, Kinds {
return mkTypeApply(tree, tparams, restype, targs);
}
- /** Instantiate method `tree' of polymorphic type with given `tparams' and
- * `restype', so that resulting method type can be applied to
- * arguments with types `argtypes' and its result type is compatible with `pt'.
+ /** Instantiate method `tree' of polymorphic type [tparams]restype,
+ * so that resulting method type can be applied to arguments with
+ * types `argtypes' and its result type is compatible with `pt'.
*/
public Tree methodInstance(Tree tree,
- Symbol[] tparams, Type restype, Type[] argtypes, Type pt)
+ Symbol[] tparams, Type restype,
+ Type[] argtypes, Type pt)
throws Type.Error {
switch (restype) {
case PolyType(Symbol[] tparams1, Type restype1):
@@ -772,31 +733,33 @@ public class Infer implements Modifiers, Kinds {
System.arraycopy(tparams1, 0, tparams2, tparams.length, tparams1.length);
return methodInstance(tree, tparams2, restype1, argtypes, pt);
case MethodType(Symbol[] params, Type restpe):
- Type[] argtypes1 = Type.widen(argtypes);
Type[] targs;
try {
- targs = methTypeArgs(tparams, params, argtypes1, restpe, pt, true);
+ targs = methTypeArgs(tparams, params, argtypes, restpe, pt, true);
} catch (NoInstance ex) {
throw new Type.Error(
applyErrorMsg(
"no type parameters for ", tree,
" exist so that it can be applied to arguments ",
- argtypes1, Type.AnyType) +
+ Type.widen(argtypes), Type.AnyType) +
"\n --- because ---\n" + ex.getMessage());
}
Symbol[] uninstantiated = normalizeArgs(targs, tparams);
checkBounds(tparams, targs, "inferred ");
- Type restype1 = (uninstantiated.length == 0) ? restype
- : Type.MethodType(params,
- Type.PolyType(uninstantiated, restpe));
+ Type restype1 = (uninstantiated.length == 0)
+ ? restype
+ : Type.MethodType(
+ params, Type.PolyType(uninstantiated, restpe));
return mkTypeApply(tree, tparams, restype1, targs);
default:
return tree;
}
}
- /** Instantiate constructor `tree' of polymorphic type with given `tparams' and
- * `restype', so that its result type matches prototype `pt'.
+ /** Instantiate constructor `tree' of polymorphic type [tparams]restype',
+ * so that its the result type of `restype' matches prototype `pt'.
+ * If constructor is polymorphic, maximize all type variables under this
+ * condition.
*/
public void constructorInstance(Tree tree,
Symbol[] tparams, Type restype, Type pt)
@@ -851,7 +814,7 @@ public class Infer implements Modifiers, Kinds {
case PolyType(Symbol[] tparams, MethodType(Symbol[] params, Type restpe)):
try {
Type[] targs = methTypeArgs(
- tparams, params, Type.widen(argtypes), restpe, pt, false);
+ tparams, params, argtypes, restpe, pt, false);
if (targs != null) {
Symbol[] uninstantiated = normalizeArgs(targs, tparams);
return
@@ -888,6 +851,8 @@ public class Infer implements Modifiers, Kinds {
public void exprAlternative(Tree tree, Symbol[] alts,
Type[] alttypes, Type pt)
throws Type.Error {
+ // first, catch the case of a missing parameter
+ // list for an overloaded constructor.
if (alts.length > 0) {
int i = 0;
while (i < alts.length &&
@@ -897,10 +862,12 @@ public class Infer implements Modifiers, Kinds {
if (i == alts.length)
throw new Type.Error("missing arguments for " + alts[0]);
}
+ // then catch the case of a single alternative.
if (alts.length == 1) {
tree.setSymbol(alts[0]).setType(alttypes[0]);
return;
}
+ // finally, do the normal case.
int best = -1;
for (int i = 0; i < alttypes.length; i++) {
if (isCompatible(alttypes[i], pt) &&
@@ -958,9 +925,9 @@ public class Infer implements Modifiers, Kinds {
}
}
- /** Assign `tree' the type of unique polymorphic alternative with `nparams' numbers
- * of type parameters, if it exists.
- * throw error if several polymorphic alternatives exist.
+ /** Assign `tree' the type of unique polymorphic alternative with `nparams'
+ * as the number of type parameters, if it exists.
+ * Throw error if several such polymorphic alternatives exist.
* If no alternative matches, leave `tree' unchanged.
*/
public void polyAlternative(Tree tree,
@@ -972,12 +939,14 @@ public class Infer implements Modifiers, Kinds {
}
int i = 0;
while (i < alttypes.length &&
- !(alts[i].isValue() && alttypes[i].typeParams().length == nparams)) {
+ !(alts[i].isValue() &&
+ alttypes[i].typeParams().length == nparams)) {
i++;
}
if (i < alttypes.length) {
for (int j = i + 1; j < alttypes.length; j++) {
- if (alts[j].isValue() && alttypes[j].typeParams().length == nparams)
+ if (alts[j].isValue() &&
+ alttypes[j].typeParams().length == nparams)
throw new Type.Error(overloadResolveErrorMsg(
alts[i], alttypes[i], alts[j], alttypes[j]));
}
diff --git a/test/files/run/lisp.scala b/test/files/run/lisp.scala
index 8c994f668c..0bcdaeb31d 100644
--- a/test/files/run/lisp.scala
+++ b/test/files/run/lisp.scala
@@ -144,14 +144,14 @@ object Lisp {
.extend("=", Lambda{
case List(arg1, arg2) => if(arg1 == arg2) 1 else 0})
.extend("+", Lambda{
- case List(arg1: int, arg2: int) => asInt(arg1) + asInt(arg2)
- case List(arg1: String, arg2: String) => asString(arg1) + asString(arg2)})
+ case List(arg1: int, arg2: int) => arg1 + arg2
+ case List(arg1: String, arg2: String) => arg1 + arg2})
.extend("-", Lambda{
- case List(arg1, arg2) => asInt(arg1) - asInt(arg2)})
+ case List(arg1: int, arg2: int) => arg1 - arg2})
.extend("*", Lambda{
- case List(arg1, arg2) => asInt(arg1) * asInt(arg2)})
+ case List(arg1: int, arg2: int) => arg1 * arg2})
.extend("/", Lambda{
- case List(arg1, arg2) => asInt(arg1) / asInt(arg2)})
+ case List(arg1: int, arg2: int) => arg1 / arg2})
.extend("nil", Nil)
.extend("cons", Lambda{
case List(arg1, arg2) => arg1 :: asList(arg2)})