diff options
34 files changed, 506 insertions, 56 deletions
diff --git a/config/list/examples.lst b/config/list/examples.lst index d568a7e494..f632cfde16 100644 --- a/config/list/examples.lst +++ b/config/list/examples.lst @@ -2,12 +2,13 @@ # scala examples (paths are relative to ./sources/examples) ############################################################################## -ComputeServer.scala -auction.scala -boundedbuffer.scala -buffer1.scala +concurrent/ComputeServer.scala +concurrent/auction.scala +concurrent/boundedbuffer.scala +concurrent/buffer1.scala +concurrent/futures.scala + fors.scala -futures.scala iterators.scala maps.scala parsers.scala diff --git a/config/list/library.lst b/config/list/library.lst index eaf9372fbe..f3d82effe4 100644 --- a/config/list/library.lst +++ b/config/list/library.lst @@ -110,6 +110,7 @@ collection/immutable/Queue.scala collection/immutable/Set.scala collection/immutable/Stack.scala +concurrent/LinkedList.scala concurrent/Actor.scala concurrent/MailBox.scala concurrent/Channel.scala diff --git a/doc/reference/ScalaByExample.tex b/doc/reference/ScalaByExample.tex index 4885f7457f..850cc53eec 100644 --- a/doc/reference/ScalaByExample.tex +++ b/doc/reference/ScalaByExample.tex @@ -6381,14 +6381,19 @@ class ReadersWriters { \section{Asynchronous Channels} A fundamental way of interprocess communication is the asynchronous -channel. Its implementation makes use the following class for linked +channel. Its implementation makes use the following simple class for linked lists: \begin{lstlisting} -package scala.collection.mutable; -class LinkedList[A](head: A, tail: LinkedList[A]) - extends SingleLinkedList[A, LinkedList[A]] { - elem = head; - next = tail; +class LinkedList[a] { + var elem: a = _; + var next: LinkedList[a] = null; + def insert(elem: a): LinkedList[a] = { + val nx = new LinkedList[a]; + nx.elem = a; + nx.next = next; + next = nx; + next + } } \end{lstlisting} To facilitate insertion and deletion of elements into linked lists, @@ -6402,14 +6407,15 @@ wish to read from an empty channel, register their presence by incrementing the \code{nreaders} field and waiting to be notified. \begin{lstlisting} package scala.concurrent; + class Channel[a] with Monitor { - var dummy: a = _; - private var written = new LinkedList[a](dummy, null); + private var written = new LinkedList[a]; private var lastWritten = written; private var nreaders = 0; def write(x: a) = synchronized { - lastWritten.next = new LinkedList(x, null); + lastWritten.elem = x; + lastWritten.next = new LinkedList[a]; lastWritten = lastWritten.next; if (nreaders > 0) notify(); } @@ -6565,26 +6571,26 @@ class MailBox { def receiveWithin[a](msec: long)(f: PartialFunction[Any, a]): a; } \end{lstlisting} -The state of a message space consists of a multi-set of messages. -Messages are added to the space using the \code{send} method. Messages +The state of a mailbox consists of a multi-set of messages. +Messages are added to the mailbox the \code{send} method. Messages are removed using the \code{receive} method, which is passed a message processor \code{f} as argument, which is a partial function from messages to some arbitrary result type. Typically, this function is implemented as a pattern matching expression. The \code{receive} -method blocks until there is a message in the space for which its +method blocks until there is a message in the mailbox for which its message processor is defined. The matching message is then removed -from the space and the blocked thread is restarted by applying the +from the mailbox and the blocked thread is restarted by applying the message processor to the message. Both sent messages and receivers are ordered in time. A receiver $r$ is applied to a matching message $m$ only if there is no other (message, receiver) pair which precedes $(m, r)$ in the partial ordering on pairs that orders each component in time. -As a simple example of how message spaces are used, consider a +As a simple example of how mailboxes are used, consider a one-place buffer: \begin{lstlisting} class OnePlaceBuffer { - private val m = new MessageSpace; // An internal message space + private val m = new MailBox; // An internal milbox private case class Empty, Full(x: int); // Types of messages we deal with m send Empty; // Initialization def write(x: int): unit = @@ -6593,9 +6599,9 @@ class OnePlaceBuffer { m receive { case Full(x) => m send Empty ; x } } \end{lstlisting} -Here's how the message space class can be implemented: +Here's how the mailbox class can be implemented: \begin{lstlisting} -class MessageSpace { +class MailBox with Monitor { private abstract class Receiver extends Signal { def isDefined(msg: Any): boolean; var msg = null; @@ -6609,12 +6615,12 @@ receiver thread. When the receiver thread is woken up, the message it needs to be applied to is stored in the \code{msg} variable of \code{Receiver}. \begin{lstlisting} - private val sent = new LinkedList[Any](null) ; + private val sent = new LinkedList[Any]; private var lastSent = sent; - private var receivers = new LinkedList[Receiver](null); + private val receivers = new LinkedList[Receiver]; private var lastReceiver = receivers; \end{lstlisting} -The message space class maintains two linked lists, +The mailbox class maintains two linked lists, one for sent but unconsumed messages, the other for waiting receivers. \begin{lstlisting} def send(msg: Any): unit = synchronized { @@ -6625,30 +6631,28 @@ one for sent but unconsumed messages, the other for waiting receivers. if (r1 != null) { r.next = r1.next; r1.elem.msg = msg; r1.elem.notify; } else { - l = new LinkedList(msg); lastSent.next = l; lastSent = l; + lastSent = lastSent.insert(msg); } } \end{lstlisting} The \code{send} method first checks whether a waiting receiver is - applicable to the sent message. If yes, the receiver is notified. Otherwise, the message is appended to the linked list of sent messages. \begin{lstlisting} def receive[a](f: PartialFunction[Any, a]): a = { val msg: Any = synchronized { var s = sent, s1 = s.next; - while (s1 != null && !f.isDefined(s1.elem)) { + while (s1 != null && !f.isDefinedAt(s1.elem)) { s = s1; s1 = s1.next } if (s1 != null) { s.next = s1.next; s1.elem } else { - val r = new LinkedList( - new Receiver { - def isDefined(msg: Any) = f.isDefined(msg); - }); - lastReceiver.next = r; lastReceiver = r; - r.elem.wait; + val r = lastReceiver.insert(new Receiver { + def isDefined(msg: Any) = f.isDefinedAt(msg); + }); + lastReceiver = r; + r.elem.wait(); r.elem.msg } } @@ -6663,7 +6667,7 @@ and linked into the \code{receivers} list, and the thread waits for a notification on this receiver. Once the thread is woken up again, it continues by applying \code{f} to the message that was stored in the receiver. -The message space class also offers a method \code{receiveWithin} +The mailbox class also offers a method \code{receiveWithin} which blocks for only a specified maximal amount of time. If no message is received within the specified time interval (given in milliseconds), the message processor argument $f$ will be unblocked @@ -6673,18 +6677,16 @@ with the special \code{TIMEOUT} message. The implementation of def receiveWithin[a](msec: long)(f: PartialFunction[Any, a]): a = { val msg: Any = synchronized { var s = sent, s1 = s.next; - while (s1 != null && !f.isDefined(s1.elem)) { + while (s1 != null && !f.isDefinedAt(s1.elem)) { s = s1; s1 = s1.next ; } if (s1 != null) { s.next = s1.next; s1.elem } else { - val r = new LinkedList( - new Receiver { - def isDefined(msg: Any) = f.isDefined(msg); - } - ) - lastReceiver.next = r; lastReceiver = r; + val r = lastReceiver.insert(new Receiver { + def isDefined(msg: Any) = f.isDefinedAt(msg); + }); + lastReceiver = r; r.elem.wait(msec); if (r.elem.msg == null) r.elem.msg = TIMEOUT; r.elem.msg @@ -6692,7 +6694,7 @@ with the special \code{TIMEOUT} message. The implementation of } f(msg) } -} // end MessageSpace +} // end MailBox \end{lstlisting} The only differences are the timed call to \code{wait}, and the statement following it. @@ -6704,10 +6706,25 @@ Chapter~\ref{sec:ex-auction} sketched as a program example the implementation of an electronic auction service. This service was based on high-level actor processes, that work by inspecting messages in their mailbox using pattern matching. An actor is simply a thread -whose communication primitives are those of a message space. -Actors are therefore defined by a mixin composition of threads and message spaces. +whose communication primitives are those of a mailbox. Actors are +defined as an extension of Java's standard \code{Thread} class which +forwards all communication calls to an internal mailbox. \begin{lstlisting} -abstract class Actor extends Thread with MessageSpace; +abstract class Actor extends Thread { + + type Message = Any; + + private val mb = new MailBox; + + def send(msg: Message): unit = + mb.send(msg); + + protected def receive[a](f: PartialFunction[Message, a]): a = + mb.receive(f); + + protected def receiveWithin[a](msec: long)(f: PartialFunction[Message, a]): a = + mb.receiveWithin(msec)(f); +} \end{lstlisting} \comment{ @@ -7236,8 +7253,7 @@ The function \code{sumLeaves} sums up all the integer values in the leaves of a given tree \code{t}. It is is implemented by calling the \code{match} method of \code{t} with a {\em choice expression} as argument (\code{match} is a predefined method in class \code{Object}). -The choice expression consists of two cases which both -relate a pattern with an expression. The pattern of the first case, +The choice expression consists of two cases which botrelate a pattern with an expression. The pattern of the first case, \code{Branch(l, r)} matches all instances of class \code{Branch} and binds the {\em pattern variables} \code{l} and \code{r} to the constructor arguments, i.e.\ the left and right subtrees of the diff --git a/sources/scala/concurrent/Actor.scala b/sources/scala/concurrent/Actor.scala index dd4cee26d2..c86fd5dfb7 100644 --- a/sources/scala/concurrent/Actor.scala +++ b/sources/scala/concurrent/Actor.scala @@ -2,17 +2,17 @@ package scala.concurrent; abstract class Actor extends Thread() { - type Message = AnyRef; + type Message = Any; private val mb = new MailBox; def send(msg: Message): unit = mb.send(msg); - def receive[a](f: PartialFunction[Message, a]): a = + protected def receive[a](f: PartialFunction[Message, a]): a = mb.receive(f); - def receiveWithin[a](msec: long)(f: PartialFunction[Message, a]): a = + protected def receiveWithin[a](msec: long)(f: PartialFunction[Message, a]): a = mb.receiveWithin(msec)(f); } diff --git a/sources/scala/concurrent/Channel.scala b/sources/scala/concurrent/Channel.scala index e82568b956..b89e20f065 100644 --- a/sources/scala/concurrent/Channel.scala +++ b/sources/scala/concurrent/Channel.scala @@ -1,16 +1,14 @@ package scala.concurrent; -import scala.collection.mutable.LinkedList; - class Channel[a] with Monitor { - var dummy: a = _; - private var written = new LinkedList[a](dummy, null); + private var written = new LinkedList[a]; private var lastWritten = written; private var nreaders = 0; def write(x: a) = synchronized { - lastWritten.next = new LinkedList(x, null); + lastWritten.next = new LinkedList[a]; lastWritten = lastWritten.next; + lastWritten.elem = x; if (nreaders > 0) notify(); } diff --git a/sources/scala/concurrent/LinkedList.scala b/sources/scala/concurrent/LinkedList.scala new file mode 100644 index 0000000000..7e9358b36d --- /dev/null +++ b/sources/scala/concurrent/LinkedList.scala @@ -0,0 +1,12 @@ +package scala.concurrent; +class LinkedList[a] { + var elem: a = _; + var next: LinkedList[a] = null; + def insert(elem: a): LinkedList[a] = { + val nx = new LinkedList[a]; + nx.elem = elem; + nx.next = next; + next = nx; + next + } +} diff --git a/test/files/neg/182.check b/test/files/neg/182.check new file mode 100644 index 0000000000..d5370cd43b --- /dev/null +++ b/test/files/neg/182.check @@ -0,0 +1,5 @@ +bug182.scala:2: error overriding class Foo.I in class Foo; + class Bar.I in class Bar cannot override a class +class Bar extends Foo { class I; } + ^ +one error found diff --git a/test/files/neg/bug144.check b/test/files/neg/bug144.check new file mode 100644 index 0000000000..3342654b90 --- /dev/null +++ b/test/files/neg/bug144.check @@ -0,0 +1,4 @@ +bug144.scala:2: trait I is inherited twice +class C with I with I; + ^ +one error found diff --git a/test/files/neg/bug144.scala b/test/files/neg/bug144.scala new file mode 100644 index 0000000000..5702ed7224 --- /dev/null +++ b/test/files/neg/bug144.scala @@ -0,0 +1,2 @@ +trait I; +class C with I with I; diff --git a/test/files/neg/bug152.check b/test/files/neg/bug152.check new file mode 100644 index 0000000000..fddfbfa879 --- /dev/null +++ b/test/files/neg/bug152.check @@ -0,0 +1,4 @@ +bug152.scala:5: type foo.type escapes its defining scope as part of scala.Object { def a: foo.T } +class Bar(foo: Foo) { + ^ +one error found diff --git a/test/files/neg/bug152.scala b/test/files/neg/bug152.scala new file mode 100644 index 0000000000..c35fe00012 --- /dev/null +++ b/test/files/neg/bug152.scala @@ -0,0 +1,7 @@ +abstract class Foo { + type T; +} + +class Bar(foo: Foo) { + def a: foo.T = a; +} diff --git a/test/files/neg/bug169.check b/test/files/neg/bug169.check new file mode 100644 index 0000000000..4bd0c592fc --- /dev/null +++ b/test/files/neg/bug169.check @@ -0,0 +1,7 @@ +bug169.scala:8: not found: type TIMEOUT + case TIMEOUT() => { + ^ +bug169.scala:9: value ! is not a member of java.lang.Process + Child ! 'foo; + ^ +two errors found diff --git a/test/files/neg/bug169.scala b/test/files/neg/bug169.scala new file mode 100644 index 0000000000..28f1853a68 --- /dev/null +++ b/test/files/neg/bug169.scala @@ -0,0 +1,14 @@ +import scala.concurrent.Process._; + +class D() { + def start_listener(Child:Process) = { + var running = true; + while (running) { + receiveWithin(0) { + case TIMEOUT() => { + Child ! 'foo; + } + } + } + } +} diff --git a/test/files/neg/bug228.check b/test/files/neg/bug228.check new file mode 100644 index 0000000000..0dc891bced --- /dev/null +++ b/test/files/neg/bug228.check @@ -0,0 +1,4 @@ +/home/odersky/scala/test/pos/bug228.scala:11: constructor java.lang.reflect.AccessibleObject cannot be accessed in Foo + val o = new AccessibleObject; + ^ +one error found diff --git a/test/files/neg/bug228.scala b/test/files/neg/bug228.scala new file mode 100644 index 0000000000..55e4a8f818 --- /dev/null +++ b/test/files/neg/bug228.scala @@ -0,0 +1,13 @@ +import java.lang.reflect.AccessibleObject; + +class Test extends AccessibleObject { + + val o = new AccessibleObject; + +} + +class Foo { + + val o = new AccessibleObject; + +} diff --git a/test/files/neg/dep.check b/test/files/neg/dep.check new file mode 100644 index 0000000000..f6a2361121 --- /dev/null +++ b/test/files/neg/dep.check @@ -0,0 +1,4 @@ +dep.scala:5: type x.type escapes its defining scope as part of x.t + def foo(x: C, y: x.t): Object = null; + ^ +one error found diff --git a/test/files/neg/dep.scala b/test/files/neg/dep.scala new file mode 100644 index 0000000000..83c005b860 --- /dev/null +++ b/test/files/neg/dep.scala @@ -0,0 +1,6 @@ +object Test { + abstract class C { + type t; + } + def foo(x: C, y: x.t): Object = null; +}
\ No newline at end of file diff --git a/test/files/pos/MailBox.scala b/test/files/pos/MailBox.scala new file mode 100644 index 0000000000..c44da9fdfa --- /dev/null +++ b/test/files/pos/MailBox.scala @@ -0,0 +1,68 @@ +package test; + +import scala.concurrent._; + +class MailBox with Monitor { + private abstract class Receiver { + def isDefined(msg: Any): boolean; + var msg: Any = null; + } + + private val sent = new LinkedList[Any]; + private var lastSent = sent; + private val receivers = new LinkedList[Receiver]; + private var lastReceiver = receivers; + + def send(msg: Any): unit = synchronized { + var r = receivers, r1 = r.next; + while (r1 != null && !r1.elem.isDefined(msg)) { + r = r1; r1 = r1.next; + } + if (r1 != null) { + r.next = r1.next; r1.elem.msg = msg; r1.elem.notify; + } else { + lastSent = lastSent.insert(msg); + } + } + + def receive[a](f: PartialFunction[Any, a]): a = { + val msg: Any = synchronized { + var s = sent, s1 = s.next; + while (s1 != null && !f.isDefinedAt(s1.elem)) { + s = s1; s1 = s1.next + } + if (s1 != null) { + s.next = s1.next; s1.elem + } else { + val r = lastReceiver.insert(new Receiver { + def isDefined(msg: Any) = f.isDefinedAt(msg); + }); + lastReceiver = r; + r.elem.wait(); + r.elem.msg + } + } + f(msg) + } + + def receiveWithin[a](msec: long)(f: PartialFunction[Any, a]): a = { + val msg: Any = synchronized { + var s = sent, s1 = s.next; + while (s1 != null && !f.isDefinedAt(s1.elem)) { + s = s1; s1 = s1.next ; + } + if (s1 != null) { + s.next = s1.next; s1.elem + } else { + val r = lastReceiver.insert(new Receiver { + def isDefined(msg: Any) = f.isDefinedAt(msg); + }); + lastReceiver = r; + r.elem.wait(msec); + if (r.elem.msg == null) r.elem.msg = TIMEOUT; + r.elem.msg + } + } + f(msg) + } +} diff --git a/test/files/pos/abstract-data.scala b/test/files/pos/abstract-data.scala new file mode 100644 index 0000000000..f3d4a966bb --- /dev/null +++ b/test/files/pos/abstract-data.scala @@ -0,0 +1,55 @@ +package expAbstractData; + +/** A base class consisting of + * - a root trait (i.e. abstract class) `Exp' with an `eval' function + * - an abstract type `exp' bounded by `Exp' + * - a concrete instance class `Num' of `Exp' for numeric literals + */ +trait Base { + type exp <: Exp; + + trait Exp { + def eval: int + } + class Num(v: int): exp extends Exp { + val value = v; + def eval = value + } +} + +object testBase extends Base with Executable { + type exp = Exp; + val term = new Num(2); + System.out.println(term.eval); +} + +/** Data extension: An extension of `Base' with `Plus' expressions + */ +trait BasePlus extends Base { + class Plus(l: exp, r: exp): exp extends Exp { + val left = l; + val right = r; + def eval = left.eval + right.eval + } +} + +/** Operation extension: An extension of `Base' with 'show' methods. + */ +trait Show extends Base { + type exp <: Exp1; + + trait Exp1 extends Exp { + def show: String; + } + class Num1(v: int): exp extends Num(v) with Exp1 { + def show = value.toString(); + } +} + +/** Operation extension: An extension of `BasePlus' with 'show' methods. + */ +trait ShowPlus extends BasePlus with Show { + class Plus1(l: exp, r: exp): exp extends Plus(l, r) with Exp1 { + def show = left.show + " + " + right.show + } +}
\ No newline at end of file diff --git a/test/files/pos/bug245.scala b/test/files/pos/bug245.scala new file mode 100644 index 0000000000..3e5dee820b --- /dev/null +++ b/test/files/pos/bug245.scala @@ -0,0 +1,18 @@ +class Value { + def coerce: Int = 0; +} + +object Test { + + def foo(i: Int): Int = 0; + + def fun0 : Value = null; + def fun0(i: Int ): Value = null; + + def fun1(i: Int ): Value = null; + def fun1(l: Long): Value = null; + + foo(fun0 ); + foo(fun1(new Value)); + +} diff --git a/test/neg/182.check b/test/neg/182.check new file mode 100644 index 0000000000..d5370cd43b --- /dev/null +++ b/test/neg/182.check @@ -0,0 +1,5 @@ +bug182.scala:2: error overriding class Foo.I in class Foo; + class Bar.I in class Bar cannot override a class +class Bar extends Foo { class I; } + ^ +one error found diff --git a/test/neg/bug144.check b/test/neg/bug144.check new file mode 100644 index 0000000000..3342654b90 --- /dev/null +++ b/test/neg/bug144.check @@ -0,0 +1,4 @@ +bug144.scala:2: trait I is inherited twice +class C with I with I; + ^ +one error found diff --git a/test/neg/bug144.scala b/test/neg/bug144.scala new file mode 100644 index 0000000000..5702ed7224 --- /dev/null +++ b/test/neg/bug144.scala @@ -0,0 +1,2 @@ +trait I; +class C with I with I; diff --git a/test/neg/bug152.check b/test/neg/bug152.check new file mode 100644 index 0000000000..fddfbfa879 --- /dev/null +++ b/test/neg/bug152.check @@ -0,0 +1,4 @@ +bug152.scala:5: type foo.type escapes its defining scope as part of scala.Object { def a: foo.T } +class Bar(foo: Foo) { + ^ +one error found diff --git a/test/neg/bug152.scala b/test/neg/bug152.scala new file mode 100644 index 0000000000..c35fe00012 --- /dev/null +++ b/test/neg/bug152.scala @@ -0,0 +1,7 @@ +abstract class Foo { + type T; +} + +class Bar(foo: Foo) { + def a: foo.T = a; +} diff --git a/test/neg/bug169.check b/test/neg/bug169.check new file mode 100644 index 0000000000..4bd0c592fc --- /dev/null +++ b/test/neg/bug169.check @@ -0,0 +1,7 @@ +bug169.scala:8: not found: type TIMEOUT + case TIMEOUT() => { + ^ +bug169.scala:9: value ! is not a member of java.lang.Process + Child ! 'foo; + ^ +two errors found diff --git a/test/neg/bug169.scala b/test/neg/bug169.scala new file mode 100644 index 0000000000..28f1853a68 --- /dev/null +++ b/test/neg/bug169.scala @@ -0,0 +1,14 @@ +import scala.concurrent.Process._; + +class D() { + def start_listener(Child:Process) = { + var running = true; + while (running) { + receiveWithin(0) { + case TIMEOUT() => { + Child ! 'foo; + } + } + } + } +} diff --git a/test/neg/bug228.check b/test/neg/bug228.check new file mode 100644 index 0000000000..0dc891bced --- /dev/null +++ b/test/neg/bug228.check @@ -0,0 +1,4 @@ +/home/odersky/scala/test/pos/bug228.scala:11: constructor java.lang.reflect.AccessibleObject cannot be accessed in Foo + val o = new AccessibleObject; + ^ +one error found diff --git a/test/neg/bug228.scala b/test/neg/bug228.scala new file mode 100644 index 0000000000..55e4a8f818 --- /dev/null +++ b/test/neg/bug228.scala @@ -0,0 +1,13 @@ +import java.lang.reflect.AccessibleObject; + +class Test extends AccessibleObject { + + val o = new AccessibleObject; + +} + +class Foo { + + val o = new AccessibleObject; + +} diff --git a/test/neg/dep.check b/test/neg/dep.check new file mode 100644 index 0000000000..f6a2361121 --- /dev/null +++ b/test/neg/dep.check @@ -0,0 +1,4 @@ +dep.scala:5: type x.type escapes its defining scope as part of x.t + def foo(x: C, y: x.t): Object = null; + ^ +one error found diff --git a/test/neg/dep.scala b/test/neg/dep.scala new file mode 100644 index 0000000000..83c005b860 --- /dev/null +++ b/test/neg/dep.scala @@ -0,0 +1,6 @@ +object Test { + abstract class C { + type t; + } + def foo(x: C, y: x.t): Object = null; +}
\ No newline at end of file diff --git a/test/pos/MailBox.scala b/test/pos/MailBox.scala new file mode 100644 index 0000000000..c44da9fdfa --- /dev/null +++ b/test/pos/MailBox.scala @@ -0,0 +1,68 @@ +package test; + +import scala.concurrent._; + +class MailBox with Monitor { + private abstract class Receiver { + def isDefined(msg: Any): boolean; + var msg: Any = null; + } + + private val sent = new LinkedList[Any]; + private var lastSent = sent; + private val receivers = new LinkedList[Receiver]; + private var lastReceiver = receivers; + + def send(msg: Any): unit = synchronized { + var r = receivers, r1 = r.next; + while (r1 != null && !r1.elem.isDefined(msg)) { + r = r1; r1 = r1.next; + } + if (r1 != null) { + r.next = r1.next; r1.elem.msg = msg; r1.elem.notify; + } else { + lastSent = lastSent.insert(msg); + } + } + + def receive[a](f: PartialFunction[Any, a]): a = { + val msg: Any = synchronized { + var s = sent, s1 = s.next; + while (s1 != null && !f.isDefinedAt(s1.elem)) { + s = s1; s1 = s1.next + } + if (s1 != null) { + s.next = s1.next; s1.elem + } else { + val r = lastReceiver.insert(new Receiver { + def isDefined(msg: Any) = f.isDefinedAt(msg); + }); + lastReceiver = r; + r.elem.wait(); + r.elem.msg + } + } + f(msg) + } + + def receiveWithin[a](msec: long)(f: PartialFunction[Any, a]): a = { + val msg: Any = synchronized { + var s = sent, s1 = s.next; + while (s1 != null && !f.isDefinedAt(s1.elem)) { + s = s1; s1 = s1.next ; + } + if (s1 != null) { + s.next = s1.next; s1.elem + } else { + val r = lastReceiver.insert(new Receiver { + def isDefined(msg: Any) = f.isDefinedAt(msg); + }); + lastReceiver = r; + r.elem.wait(msec); + if (r.elem.msg == null) r.elem.msg = TIMEOUT; + r.elem.msg + } + } + f(msg) + } +} diff --git a/test/pos/abstract-data.scala b/test/pos/abstract-data.scala new file mode 100644 index 0000000000..f3d4a966bb --- /dev/null +++ b/test/pos/abstract-data.scala @@ -0,0 +1,55 @@ +package expAbstractData; + +/** A base class consisting of + * - a root trait (i.e. abstract class) `Exp' with an `eval' function + * - an abstract type `exp' bounded by `Exp' + * - a concrete instance class `Num' of `Exp' for numeric literals + */ +trait Base { + type exp <: Exp; + + trait Exp { + def eval: int + } + class Num(v: int): exp extends Exp { + val value = v; + def eval = value + } +} + +object testBase extends Base with Executable { + type exp = Exp; + val term = new Num(2); + System.out.println(term.eval); +} + +/** Data extension: An extension of `Base' with `Plus' expressions + */ +trait BasePlus extends Base { + class Plus(l: exp, r: exp): exp extends Exp { + val left = l; + val right = r; + def eval = left.eval + right.eval + } +} + +/** Operation extension: An extension of `Base' with 'show' methods. + */ +trait Show extends Base { + type exp <: Exp1; + + trait Exp1 extends Exp { + def show: String; + } + class Num1(v: int): exp extends Num(v) with Exp1 { + def show = value.toString(); + } +} + +/** Operation extension: An extension of `BasePlus' with 'show' methods. + */ +trait ShowPlus extends BasePlus with Show { + class Plus1(l: exp, r: exp): exp extends Plus(l, r) with Exp1 { + def show = left.show + " + " + right.show + } +}
\ No newline at end of file diff --git a/test/pos/bug245.scala b/test/pos/bug245.scala new file mode 100644 index 0000000000..3e5dee820b --- /dev/null +++ b/test/pos/bug245.scala @@ -0,0 +1,18 @@ +class Value { + def coerce: Int = 0; +} + +object Test { + + def foo(i: Int): Int = 0; + + def fun0 : Value = null; + def fun0(i: Int ): Value = null; + + def fun1(i: Int ): Value = null; + def fun1(l: Long): Value = null; + + foo(fun0 ); + foo(fun1(new Value)); + +} |