diff options
109 files changed, 1889 insertions, 856 deletions
diff --git a/src/actors/scala/actors/Actor.scala b/src/actors/scala/actors/Actor.scala index 907389b9f0..838d3a8f63 100644 --- a/src/actors/scala/actors/Actor.scala +++ b/src/actors/scala/actors/Actor.scala @@ -160,7 +160,7 @@ object Actor { * @param f a partial function specifying patterns and actions * @return the result of processing the received message */ - def receive[A](f: Any =>? A): A = + def receive[A](f: PartialFunction[Any, A]): A = self.receive(f) /** @@ -175,7 +175,7 @@ object Actor { * @param f a partial function specifying patterns and actions * @return the result of processing the received message */ - def receiveWithin[R](msec: Long)(f: Any =>? R): R = + def receiveWithin[R](msec: Long)(f: PartialFunction[Any, R]): R = self.receiveWithin(msec)(f) /** @@ -188,7 +188,7 @@ object Actor { * @param f a partial function specifying patterns and actions * @return this function never returns */ - def react(f: Any =>? Unit): Nothing = + def react(f: PartialFunction[Any, Unit]): Nothing = rawSelf.react(f) /** @@ -202,14 +202,14 @@ object Actor { * @param f a partial function specifying patterns and actions * @return this function never returns */ - def reactWithin(msec: Long)(f: Any =>? Unit): Nothing = + def reactWithin(msec: Long)(f: PartialFunction[Any, Unit]): Nothing = self.reactWithin(msec)(f) - def eventloop(f: Any =>? Unit): Nothing = + def eventloop(f: PartialFunction[Any, Unit]): Nothing = rawSelf.react(new RecursiveProxyHandler(rawSelf, f)) - private class RecursiveProxyHandler(a: Reactor, f: Any =>? Unit) - extends (Any =>? Unit) { + private class RecursiveProxyHandler(a: Reactor, f: PartialFunction[Any, Unit]) + extends PartialFunction[Any, Unit] { def isDefinedAt(m: Any): Boolean = true // events are immediately removed from the mailbox def apply(m: Any) { @@ -261,9 +261,9 @@ object Actor { * } * </pre> */ - def respondOn[A, B](fun: A =>? Unit => Nothing): - A =>? B => Responder[B] = - (caseBlock: A =>? B) => new Responder[B] { + def respondOn[A, B](fun: PartialFunction[A, Unit] => Nothing): + PartialFunction[A, B] => Responder[B] = + (caseBlock: PartialFunction[A, B]) => new Responder[B] { def respond(k: B => Unit) = fun(caseBlock andThen k) } @@ -400,7 +400,7 @@ trait Actor extends AbstractActor with ReplyReactor with ReplyableActor { protected[actors] override def scheduler: IScheduler = Scheduler - private[actors] override def startSearch(msg: Any, replyTo: OutputChannel[Any], handler: Any => Boolean) = + private[actors] override def startSearch(msg: Any, replyTo: OutputChannel[Any], handler: PartialFunction[Any, Any]) = if (isSuspended) { () => synchronized { mailbox.append(msg, replyTo) @@ -411,7 +411,7 @@ trait Actor extends AbstractActor with ReplyReactor with ReplyableActor { private[actors] override def makeReaction(fun: () => Unit): Runnable = new ActorTask(this, fun) - private[actors] override def resumeReceiver(item: (Any, OutputChannel[Any]), onSameThread: Boolean) { + private[actors] override def resumeReceiver(item: (Any, OutputChannel[Any]), handler: PartialFunction[Any, Any], onSameThread: Boolean) { synchronized { if (!onTimeout.isEmpty) { onTimeout.get.cancel() @@ -419,7 +419,7 @@ trait Actor extends AbstractActor with ReplyReactor with ReplyableActor { } } senders = List(item._2) - super.resumeReceiver(item, onSameThread) + super.resumeReceiver(item, handler, onSameThread) } /** @@ -428,7 +428,7 @@ trait Actor extends AbstractActor with ReplyReactor with ReplyableActor { * @param f a partial function with message patterns and actions * @return result of processing the received value */ - def receive[R](f: Any =>? R): R = { + def receive[R](f: PartialFunction[Any, R]): R = { assert(Actor.self(scheduler) == this, "receive from channel belonging to other actor") synchronized { @@ -451,7 +451,7 @@ trait Actor extends AbstractActor with ReplyReactor with ReplyableActor { drainSendBuffer(mailbox) // keep going } else { - waitingFor = f.isDefinedAt + waitingFor = f isSuspended = true scheduler.managedBlock(blocker) drainSendBuffer(mailbox) @@ -479,7 +479,7 @@ trait Actor extends AbstractActor with ReplyReactor with ReplyableActor { * @param f a partial function with message patterns and actions * @return result of processing the received value */ - def receiveWithin[R](msec: Long)(f: Any =>? R): R = { + def receiveWithin[R](msec: Long)(f: PartialFunction[Any, R]): R = { assert(Actor.self(scheduler) == this, "receive from channel belonging to other actor") synchronized { @@ -517,7 +517,7 @@ trait Actor extends AbstractActor with ReplyReactor with ReplyableActor { done = true receiveTimeout } else { - waitingFor = f.isDefinedAt + waitingFor = f received = None isSuspended = true val thisActor = this @@ -559,14 +559,13 @@ trait Actor extends AbstractActor with ReplyReactor with ReplyableActor { * * @param f a partial function with message patterns and actions */ - override def react(f: Any =>? Unit): Nothing = { + override def react(f: PartialFunction[Any, Unit]): Nothing = { assert(Actor.self(scheduler) == this, "react on channel belonging to other actor") synchronized { if (shouldExit) exit() // links drainSendBuffer(mailbox) } - continuation = f - searchMailbox(mailbox, f.isDefinedAt, false) + searchMailbox(mailbox, f, false) throw Actor.suspendException } @@ -580,7 +579,7 @@ trait Actor extends AbstractActor with ReplyReactor with ReplyableActor { * @param msec the time span before timeout * @param f a partial function with message patterns and actions */ - def reactWithin(msec: Long)(f: Any =>? Unit): Nothing = { + def reactWithin(msec: Long)(f: PartialFunction[Any, Unit]): Nothing = { assert(Actor.self(scheduler) == this, "react on channel belonging to other actor") synchronized { @@ -616,8 +615,7 @@ trait Actor extends AbstractActor with ReplyReactor with ReplyableActor { done = true receiveTimeout } else { - waitingFor = f.isDefinedAt - continuation = f + waitingFor = f val thisActor = this onTimeout = Some(new TimerTask { def run() { thisActor.send(TIMEOUT, thisActor) } @@ -647,14 +645,12 @@ trait Actor extends AbstractActor with ReplyReactor with ReplyableActor { // guarded by lock of this // never throws SuspendActorException - private[actors] override def scheduleActor(f: Any =>? Unit, msg: Any) = - if ((f eq null) && (continuation eq null)) { + private[actors] override def scheduleActor(f: PartialFunction[Any, Any], msg: Any) = + if (f eq null) { // do nothing (timeout is handled instead) } else { - val task = new Reaction(this, - if (f eq null) continuation else f, - msg) + val task = new Reaction(this, f, msg) scheduler executeFromActor task } @@ -825,7 +821,7 @@ trait Actor extends AbstractActor with ReplyReactor with ReplyableActor { if (isSuspended) resumeActor() else if (waitingFor ne waitingForNone) { - scheduleActor(continuation, null) + scheduleActor(waitingFor, null) /* Here we should not throw a SuspendActorException, since the current method is called from an actor that is in the process of exiting. diff --git a/src/actors/scala/actors/Channel.scala b/src/actors/scala/actors/Channel.scala index 1454f29214..24340d22f2 100644 --- a/src/actors/scala/actors/Channel.scala +++ b/src/actors/scala/actors/Channel.scala @@ -76,7 +76,7 @@ class Channel[Msg](val receiver: Actor) extends InputChannel[Msg] with OutputCha * @param f a partial function with message patterns and actions * @return result of processing the received value */ - def receive[R](f: Msg =>? R): R = { + def receive[R](f: PartialFunction[Msg, R]): R = { val C = this.asInstanceOf[Channel[Any]] val recvActor = receiver.asInstanceOf[Actor] recvActor.receive { @@ -99,7 +99,7 @@ class Channel[Msg](val receiver: Actor) extends InputChannel[Msg] with OutputCha * @param f a partial function with message patterns and actions * @return result of processing the received value */ - def receiveWithin[R](msec: Long)(f: Any =>? R): R = { + def receiveWithin[R](msec: Long)(f: PartialFunction[Any, R]): R = { val C = this.asInstanceOf[Channel[Any]] val recvActor = receiver.asInstanceOf[Actor] recvActor.receiveWithin(msec) { @@ -116,7 +116,7 @@ class Channel[Msg](val receiver: Actor) extends InputChannel[Msg] with OutputCha * * @param f a partial function with message patterns and actions */ - def react(f: Msg =>? Unit): Nothing = { + def react(f: PartialFunction[Msg, Unit]): Nothing = { val C = this.asInstanceOf[Channel[Any]] receiver.react { case C ! msg if (f.isDefinedAt(msg.asInstanceOf[Msg])) => f(msg.asInstanceOf[Msg]) @@ -133,7 +133,7 @@ class Channel[Msg](val receiver: Actor) extends InputChannel[Msg] with OutputCha * @param msec the time span before timeout * @param f a partial function with message patterns and actions */ - def reactWithin(msec: Long)(f: Any =>? Unit): Nothing = { + def reactWithin(msec: Long)(f: PartialFunction[Any, Unit]): Nothing = { val C = this.asInstanceOf[Channel[Any]] val recvActor = receiver.asInstanceOf[Actor] recvActor.reactWithin(msec) { diff --git a/src/actors/scala/actors/Future.scala b/src/actors/scala/actors/Future.scala index 1369ed6255..ebb0489d88 100644 --- a/src/actors/scala/actors/Future.scala +++ b/src/actors/scala/actors/Future.scala @@ -153,7 +153,7 @@ object Futures { val partFuns = unsetFts.map((p: Pair[Int, Future[Any]]) => { val FutCh = p._2.inputChannel - val singleCase: Any =>? Pair[Int, Any] = { + val singleCase: PartialFunction[Any, Pair[Int, Any]] = { case FutCh ! any => Pair(p._1, any) } singleCase @@ -165,8 +165,8 @@ object Futures { } Actor.timer.schedule(timerTask, timeout) - def awaitWith(partFuns: Seq[Any =>? Pair[Int, Any]]) { - val reaction: Any =>? Unit = new (Any =>? Unit) { + def awaitWith(partFuns: Seq[PartialFunction[Any, Pair[Int, Any]]]) { + val reaction: PartialFunction[Any, Unit] = new PartialFunction[Any, Unit] { def isDefinedAt(msg: Any) = msg match { case TIMEOUT => true case _ => partFuns exists (_ isDefinedAt msg) diff --git a/src/actors/scala/actors/InputChannel.scala b/src/actors/scala/actors/InputChannel.scala index fb922f27b2..46988159fa 100644 --- a/src/actors/scala/actors/InputChannel.scala +++ b/src/actors/scala/actors/InputChannel.scala @@ -25,7 +25,7 @@ trait InputChannel[+Msg] { * @param f a partial function with message patterns and actions * @return result of processing the received value */ - def receive[R](f: Msg =>? R): R + def receive[R](f: PartialFunction[Msg, R]): R /** * Receives a message from this <code>InputChannel</code> within @@ -35,7 +35,7 @@ trait InputChannel[+Msg] { * @param f a partial function with message patterns and actions * @return result of processing the received value */ - def receiveWithin[R](msec: Long)(f: Any =>? R): R + def receiveWithin[R](msec: Long)(f: PartialFunction[Any, R]): R /** * Receives a message from this <code>InputChannel</code>. @@ -45,7 +45,7 @@ trait InputChannel[+Msg] { * * @param f a partial function with message patterns and actions */ - def react(f: Msg =>? Unit): Nothing + def react(f: PartialFunction[Msg, Unit]): Nothing /** * Receives a message from this <code>InputChannel</code> within @@ -57,7 +57,7 @@ trait InputChannel[+Msg] { * @param msec the time span before timeout * @param f a partial function with message patterns and actions */ - def reactWithin(msec: Long)(f: Any =>? Unit): Nothing + def reactWithin(msec: Long)(f: PartialFunction[Any, Unit]): Nothing /** * Receives the next message from this <code>Channel</code>. diff --git a/src/actors/scala/actors/MessageQueue.scala b/src/actors/scala/actors/MessageQueue.scala index fd43e36fff..000ff1bfc6 100644 --- a/src/actors/scala/actors/MessageQueue.scala +++ b/src/actors/scala/actors/MessageQueue.scala @@ -62,6 +62,15 @@ private[actors] class MQueue(protected val label: String) { last = el } + def append(el: MQueueElement) { + changeSize(1) // size always increases by 1 + + if (isEmpty) first = el + else last.next = el + + last = el + } + def foreach(f: (Any, OutputChannel[Any]) => Unit) { var curr = first while (curr != null) { @@ -70,6 +79,25 @@ private[actors] class MQueue(protected val label: String) { } } + def foreachAppend(target: MQueue) { + var curr = first + while (curr != null) { + target.append(curr) + curr = curr.next + } + } + + def foreachDequeue(target: MQueue) { + var curr = first + while (curr != null) { + target.append(curr) + curr = curr.next + } + first = null + last = null + _size = 0 + } + def foldLeft[B](z: B)(f: (B, Any) => B): B = { var acc = z var curr = first @@ -108,6 +136,43 @@ private[actors] class MQueue(protected val label: String) { def extractFirst(p: (Any, OutputChannel[Any]) => Boolean): MQueueElement = removeInternal(0)(p) orNull + def extractFirst(pf: PartialFunction[Any, Any]): MQueueElement = { + if (isEmpty) // early return + return null + + // special handling if returning the head + if (pf.isDefinedAt(first.msg)) { + val res = first + first = first.next + if (res eq last) + last = null + + changeSize(-1) + res + } + else { + var curr = first.next // init to element #2 + var prev = first + + while (curr != null) { + if (pf.isDefinedAt(curr.msg)) { + prev.next = curr.next + if (curr eq last) + last = prev + + changeSize(-1) + return curr // early return + } + else { + prev = curr + curr = curr.next + } + } + // not found + null + } + } + private def removeInternal(n: Int)(p: (Any, OutputChannel[Any]) => Boolean): Option[MQueueElement] = { var pos = 0 diff --git a/src/actors/scala/actors/ReactChannel.scala b/src/actors/scala/actors/ReactChannel.scala index 926805fbe7..8bbbc04f53 100644 --- a/src/actors/scala/actors/ReactChannel.scala +++ b/src/actors/scala/actors/ReactChannel.scala @@ -55,7 +55,7 @@ private[actors] class ReactChannel[Msg](receiver: Reactor) extends InputChannel[ * * @param f a partial function with message patterns and actions */ - def react(f: Msg =>? Unit): Nothing = { + def react(f: PartialFunction[Msg, Unit]): Nothing = { val C = this receiver.react { case SendToReactor(C, msg) if (f.isDefinedAt(msg.asInstanceOf[Msg])) => @@ -73,7 +73,7 @@ private[actors] class ReactChannel[Msg](receiver: Reactor) extends InputChannel[ * @param msec the time span before timeout * @param f a partial function with message patterns and actions */ - def reactWithin(msec: Long)(f: Any =>? Unit): Nothing = { + def reactWithin(msec: Long)(f: PartialFunction[Any, Unit]): Nothing = { val C = this val recvActor = receiver.asInstanceOf[Actor] recvActor.reactWithin(msec) { @@ -89,7 +89,7 @@ private[actors] class ReactChannel[Msg](receiver: Reactor) extends InputChannel[ * @param f a partial function with message patterns and actions * @return result of processing the received value */ - def receive[R](f: Msg =>? R): R = { + def receive[R](f: PartialFunction[Msg, R]): R = { val C = this val recvActor = receiver.asInstanceOf[Actor] recvActor.receive { @@ -106,7 +106,7 @@ private[actors] class ReactChannel[Msg](receiver: Reactor) extends InputChannel[ * @param f a partial function with message patterns and actions * @return result of processing the received value */ - def receiveWithin[R](msec: Long)(f: Any =>? R): R = { + def receiveWithin[R](msec: Long)(f: PartialFunction[Any, R]): R = { val C = this val recvActor = receiver.asInstanceOf[Actor] recvActor.receiveWithin(msec) { diff --git a/src/actors/scala/actors/Reaction.scala b/src/actors/scala/actors/Reaction.scala index a4736f9489..753dd7da83 100644 --- a/src/actors/scala/actors/Reaction.scala +++ b/src/actors/scala/actors/Reaction.scala @@ -26,7 +26,7 @@ private[actors] class KillActorException extends Throwable with ControlException * @deprecated("this class is going to be removed in a future release") * @author Philipp Haller */ -class Reaction(a: Actor, f: Any =>? Unit, msg: Any) extends ActorTask(a, () => { +class Reaction(a: Actor, f: PartialFunction[Any, Any], msg: Any) extends ActorTask(a, () => { if (f == null) a.act() else diff --git a/src/actors/scala/actors/Reactor.scala b/src/actors/scala/actors/Reactor.scala index 8545b92d1e..eb0485263b 100644 --- a/src/actors/scala/actors/Reactor.scala +++ b/src/actors/scala/actors/Reactor.scala @@ -35,25 +35,24 @@ trait Reactor extends OutputChannel[Any] { private[actors] val mailbox = new MQueue("Reactor") // guarded by this - private[actors] val sendBuffer = new Queue[(Any, OutputChannel[Any])] + private[actors] val sendBuffer = new MQueue("SendBuffer") - /* If the actor waits in a react, continuation holds the - * message handler that react was called with. - */ - @volatile - private[actors] var continuation: Any =>? Unit = null - - /* Whenever this Actor executes on some thread, waitingFor is + /* Whenever this actor executes on some thread, waitingFor is * guaranteed to be equal to waitingForNone. * * In other words, whenever waitingFor is not equal to - * waitingForNone, this Actor is guaranteed not to execute on some + * waitingForNone, this actor is guaranteed not to execute on some * thread. */ - private[actors] val waitingForNone = (m: Any) => false + private[actors] val waitingForNone = new PartialFunction[Any, Unit] { + def isDefinedAt(x: Any) = false + def apply(x: Any) {} + } - // guarded by lock of this - private[actors] var waitingFor: Any => Boolean = waitingForNone + /* If the actor waits in a react, waitingFor holds the + * message handler that react was called with. + */ + private[actors] var waitingFor: PartialFunction[Any, Any] = waitingForNone // guarded by lock of this /** * The behavior of an actor is specified by implementing this @@ -61,7 +60,7 @@ trait Reactor extends OutputChannel[Any] { */ def act(): Unit - protected[actors] def exceptionHandler: Exception =>? Unit = + protected[actors] def exceptionHandler: PartialFunction[Exception, Unit] = Map() protected[actors] def scheduler: IScheduler = @@ -84,14 +83,14 @@ trait Reactor extends OutputChannel[Any] { waitingFor = waitingForNone startSearch(msg, replyTo, savedWaitingFor) } else { - sendBuffer.enqueue((msg, replyTo)) + sendBuffer.append(msg, replyTo) () => { /* do nothing */ } } } todo() } - private[actors] def startSearch(msg: Any, replyTo: OutputChannel[Any], handler: Any => Boolean) = + private[actors] def startSearch(msg: Any, replyTo: OutputChannel[Any], handler: PartialFunction[Any, Any]) = () => scheduler execute (makeReaction(() => { val startMbox = new MQueue("Start") synchronized { startMbox.append(msg, replyTo) } @@ -101,15 +100,11 @@ trait Reactor extends OutputChannel[Any] { private[actors] def makeReaction(fun: () => Unit): Runnable = new ReactorTask(this, fun) - /* Note that this method is called without holding a lock. - * Therefore, to read an up-to-date continuation, it must be @volatile. - */ - private[actors] def resumeReceiver(item: (Any, OutputChannel[Any]), onSameThread: Boolean) { - // assert continuation != null + private[actors] def resumeReceiver(item: (Any, OutputChannel[Any]), handler: PartialFunction[Any, Any], onSameThread: Boolean) { if (onSameThread) - continuation(item._1) + handler(item._1) else { - scheduleActor(continuation, item._1) + scheduleActor(handler, item._1) /* Here, we throw a SuspendActorException to avoid terminating this actor when the current ReactorTask is finished. @@ -133,22 +128,18 @@ trait Reactor extends OutputChannel[Any] { // guarded by this private[actors] def drainSendBuffer(mbox: MQueue) { - while (!sendBuffer.isEmpty) { - val item = sendBuffer.dequeue() - mbox.append(item._1, item._2) - } + sendBuffer.foreachDequeue(mbox) } - // assume continuation != null private[actors] def searchMailbox(startMbox: MQueue, - handlesMessage: Any => Boolean, + handler: PartialFunction[Any, Any], resumeOnSameThread: Boolean) { var tmpMbox = startMbox var done = false while (!done) { - val qel = tmpMbox.extractFirst((msg: Any, replyTo: OutputChannel[Any]) => handlesMessage(msg)) + val qel = tmpMbox.extractFirst(handler) if (tmpMbox ne mailbox) - tmpMbox.foreach((m, s) => mailbox.append(m, s)) + tmpMbox.foreachAppend(mailbox) if (null eq qel) { synchronized { // in mean time new stuff might have arrived @@ -157,7 +148,7 @@ trait Reactor extends OutputChannel[Any] { drainSendBuffer(tmpMbox) // keep going } else { - waitingFor = handlesMessage + waitingFor = handler /* Here, we throw a SuspendActorException to avoid terminating this actor when the current ReactorTask is finished. @@ -169,17 +160,16 @@ trait Reactor extends OutputChannel[Any] { } } } else { - resumeReceiver((qel.msg, qel.session), resumeOnSameThread) + resumeReceiver((qel.msg, qel.session), handler, resumeOnSameThread) done = true } } } - protected[actors] def react(f: Any =>? Unit): Nothing = { + protected[actors] def react(f: PartialFunction[Any, Unit]): Nothing = { assert(Actor.rawSelf(scheduler) == this, "react on channel belonging to other actor") synchronized { drainSendBuffer(mailbox) } - continuation = f - searchMailbox(mailbox, f.isDefinedAt, false) + searchMailbox(mailbox, f, false) throw Actor.suspendException } @@ -190,7 +180,7 @@ trait Reactor extends OutputChannel[Any] { * * never throws SuspendActorException */ - private[actors] def scheduleActor(handler: Any =>? Unit, msg: Any) = { + private[actors] def scheduleActor(handler: PartialFunction[Any, Any], msg: Any) = { val fun = () => handler(msg) val task = new ReactorTask(this, fun) scheduler executeFromActor task diff --git a/src/actors/scala/actors/ReactorTask.scala b/src/actors/scala/actors/ReactorTask.scala index f6ec67e94c..37aec0f8ec 100644 --- a/src/actors/scala/actors/ReactorTask.scala +++ b/src/actors/scala/actors/ReactorTask.scala @@ -20,7 +20,7 @@ import java.util.concurrent.Callable * * @author Philipp Haller */ -private[actors] class ReactorTask[T >: Null <: Reactor](var reactor: T, var fun: () => Unit) +private[actors] class ReactorTask[T >: Null <: Reactor](var reactor: T, var fun: () => Any) extends Callable[Unit] with Runnable { def run() { diff --git a/src/actors/scala/actors/ReplyReactor.scala b/src/actors/scala/actors/ReplyReactor.scala index 64860f4d38..d5936ae662 100644 --- a/src/actors/scala/actors/ReplyReactor.scala +++ b/src/actors/scala/actors/ReplyReactor.scala @@ -52,28 +52,26 @@ trait ReplyReactor extends Reactor with ReplyableReactor { send(msg, Actor.sender) } - private[actors] override def resumeReceiver(item: (Any, OutputChannel[Any]), onSameThread: Boolean) { + private[actors] override def resumeReceiver(item: (Any, OutputChannel[Any]), handler: PartialFunction[Any, Any], onSameThread: Boolean) { senders = List(item._2) - // assert continuation != null if (onSameThread) - continuation(item._1) + handler(item._1) else { - scheduleActor(continuation, item._1) + scheduleActor(handler, item._1) // see Reactor.resumeReceiver throw Actor.suspendException } } - // assume continuation != null private[actors] override def searchMailbox(startMbox: MQueue, - handlesMessage: Any => Boolean, + handler: PartialFunction[Any, Any], resumeOnSameThread: Boolean) { var tmpMbox = startMbox var done = false while (!done) { val qel = tmpMbox.extractFirst((msg: Any, replyTo: OutputChannel[Any]) => { senders = List(replyTo) - handlesMessage(msg) + handler.isDefinedAt(msg) }) if (tmpMbox ne mailbox) tmpMbox.foreach((m, s) => mailbox.append(m, s)) @@ -85,13 +83,13 @@ trait ReplyReactor extends Reactor with ReplyableReactor { drainSendBuffer(tmpMbox) // keep going } else { - waitingFor = handlesMessage + waitingFor = handler // see Reactor.searchMailbox throw Actor.suspendException } } } else { - resumeReceiver((qel.msg, qel.session), resumeOnSameThread) + resumeReceiver((qel.msg, qel.session), handler, resumeOnSameThread) done = true } } diff --git a/src/actors/scala/actors/Replyable.scala b/src/actors/scala/actors/Replyable.scala index b1ccb3205e..2c7e55e06a 100644 --- a/src/actors/scala/actors/Replyable.scala +++ b/src/actors/scala/actors/Replyable.scala @@ -59,7 +59,7 @@ trait Replyable[-T, +R] { * @param f the function to be applied to the response * @return the future */ - def !![P](msg: T, f: R =>? P): () => P = + def !![P](msg: T, f: PartialFunction[R, P]): () => P = () => f(this !? msg) } diff --git a/src/actors/scala/actors/ReplyableActor.scala b/src/actors/scala/actors/ReplyableActor.scala index b562dbf855..2122dd854b 100644 --- a/src/actors/scala/actors/ReplyableActor.scala +++ b/src/actors/scala/actors/ReplyableActor.scala @@ -62,7 +62,7 @@ private[actors] trait ReplyableActor extends ReplyableReactor { * <code>f</code>. This also allows to recover a more * precise type for the reply value. */ - override def !![A](msg: Any, f: Any =>? A): Future[A] = { + override def !![A](msg: Any, f: PartialFunction[Any, A]): Future[A] = { val ftch = new Channel[A](Actor.self(thiz.scheduler)) thiz.send(msg, new OutputChannel[Any] { def !(msg: Any) = @@ -108,7 +108,7 @@ private[actors] trait ReplyableActor extends ReplyableReactor { Futures.fromInputChannel(someChan) } // should never be invoked; return dummy value - override def !![A](msg: Any, f: Any =>? A): Future[A] = { + override def !![A](msg: Any, f: PartialFunction[Any, A]): Future[A] = { val someChan = new Channel[A](Actor.self(thiz.scheduler)) Futures.fromInputChannel(someChan) } @@ -117,7 +117,7 @@ private[actors] trait ReplyableActor extends ReplyableReactor { thiz.send(msg, linkedChannel) new Future[Any](ftch) { var exitReason: Option[Any] = None - val handleReply: Any =>? Unit = { + val handleReply: PartialFunction[Any, Unit] = { case Exit(from, reason) => exitReason = Some(reason) case any => @@ -145,7 +145,7 @@ private[actors] trait ReplyableActor extends ReplyableReactor { def isSet = (fvalue match { case None => - val handleTimeout: Any =>? Boolean = { + val handleTimeout: PartialFunction[Any, Boolean] = { case TIMEOUT => false } diff --git a/src/actors/scala/actors/ReplyableReactor.scala b/src/actors/scala/actors/ReplyableReactor.scala index f5a2752f54..ecca50e26d 100644 --- a/src/actors/scala/actors/ReplyableReactor.scala +++ b/src/actors/scala/actors/ReplyableReactor.scala @@ -70,7 +70,7 @@ private[actors] trait ReplyableReactor extends Replyable[Any, Any] { * <code>f</code>. This also allows to recover a more * precise type for the reply value. */ - override def !![A](msg: Any, f: Any =>? A): Future[A] = { + override def !![A](msg: Any, f: PartialFunction[Any, A]): Future[A] = { val myself = Actor.rawSelf(this.scheduler) val ftch = new ReactChannel[A](myself) val res = new scala.concurrent.SyncVar[A] diff --git a/src/actors/scala/actors/remote/Proxy.scala b/src/actors/scala/actors/remote/Proxy.scala index c1744a2dfc..f9a6cd8fed 100644 --- a/src/actors/scala/actors/remote/Proxy.scala +++ b/src/actors/scala/actors/remote/Proxy.scala @@ -69,7 +69,7 @@ private[remote] class Proxy(node: Node, name: Symbol, @transient var kernel: Net override def !!(msg: Any): Future[Any] = del !! msg - override def !![A](msg: Any, f: Any =>? A): Future[A] = + override def !![A](msg: Any, f: PartialFunction[Any, A]): Future[A] = del !! (msg, f) def linkTo(to: AbstractActor): Unit = diff --git a/src/compiler/scala/tools/ant/sabbus/Settings.scala b/src/compiler/scala/tools/ant/sabbus/Settings.scala index 134b3a4bb9..2719196095 100644 --- a/src/compiler/scala/tools/ant/sabbus/Settings.scala +++ b/src/compiler/scala/tools/ant/sabbus/Settings.scala @@ -14,7 +14,6 @@ import java.io.File import org.apache.tools.ant.types.{Path, Reference} -@cloneable class Settings { private var gBf: Option[String] = None diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala index 55e3b354e5..1655c0130d 100644 --- a/src/compiler/scala/tools/nsc/Interpreter.scala +++ b/src/compiler/scala/tools/nsc/Interpreter.scala @@ -103,6 +103,18 @@ class Interpreter(val settings: Settings, out: PrintWriter) } } + /** whether to bind the lastException variable */ + private var bindLastException = true + + /** Temporarily stop binding lastException */ + def withoutBindingLastException[T](operation: => T): T = { + val wasBinding = bindLastException + ultimately(bindLastException = wasBinding) { + bindLastException = false + operation + } + } + /** interpreter settings */ lazy val isettings = new InterpreterSettings(this) @@ -477,13 +489,13 @@ class Interpreter(val settings: Settings, out: PrintWriter) val binderObject = loadByName(binderName) val setterMethod = methodByName(binderObject, "set") - // this roundabout approach is to ensure the value is boxed - var argsHolder: Array[Any] = null - argsHolder = List(value).toArray - setterMethod.invoke(null, argsHolder.asInstanceOf[Array[AnyRef]]: _*) + setterMethod.invoke(null, value.asInstanceOf[AnyRef]) interpret("val %s = %s.value".format(name, binderName)) } + def quietBind(name: String, boundType: String, value: Any): IR.Result = + beQuietDuring { bind(name, boundType, value) } + /** Reset this interpreter, forgetting all user-specified requests. */ def reset() { virtualDirectory.clear @@ -505,12 +517,14 @@ class Interpreter(val settings: Settings, out: PrintWriter) /** A traverser that finds all mentioned identifiers, i.e. things * that need to be imported. It might return extra names. */ - private class ImportVarsTraverser(definedVars: List[Name]) extends Traverser { + private class ImportVarsTraverser extends Traverser { val importVars = new HashSet[Name]() override def traverse(ast: Tree) = ast match { - case Ident(name) => importVars += name - case _ => super.traverse(ast) + // XXX this is obviously inadequate but it's going to require some effort + // to get right. + case Ident(name) if !(name.toString startsWith "x$") => importVars += name + case _ => super.traverse(ast) } } @@ -518,9 +532,9 @@ class Interpreter(val settings: Settings, out: PrintWriter) * in a single interpreter request. */ private sealed abstract class MemberHandler(val member: Tree) { - val usedNames: List[Name] = { - val ivt = new ImportVarsTraverser(boundNames) - ivt.traverseTrees(List(member)) + lazy val usedNames: List[Name] = { + val ivt = new ImportVarsTraverser() + ivt traverse member ivt.importVars.toList } def boundNames: List[Name] = Nil @@ -535,6 +549,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) def extraCodeToEvaluate(req: Request, code: PrintWriter) { } def resultExtractionCode(req: Request, code: PrintWriter) { } + override def toString = "%s(usedNames = %s)".format(this.getClass, usedNames) } private class GenericHandler(member: Tree) extends MemberHandler(member) @@ -788,9 +803,13 @@ class Interpreter(val settings: Settings, out: PrintWriter) val wrapperExceptions: List[Class[_ <: Throwable]] = List(classOf[InvocationTargetException], classOf[ExceptionInInitializerError]) - def onErr: Catcher[(String, Boolean)] = { case t: Throwable => - beQuietDuring { bind("lastException", "java.lang.Throwable", t) } - (stringFrom(t.printStackTrace(_)), false) + /** We turn off the binding to accomodate ticket #2817 */ + def onErr: Catcher[(String, Boolean)] = { + case t: Throwable if bindLastException => + withoutBindingLastException { + quietBind("lastException", "java.lang.Throwable", t) + (stringFrom(t.printStackTrace(_)), false) + } } catching(onErr) { diff --git a/src/compiler/scala/tools/nsc/InterpreterLoop.scala b/src/compiler/scala/tools/nsc/InterpreterLoop.scala index 76f09f07f7..2b926d8e80 100644 --- a/src/compiler/scala/tools/nsc/InterpreterLoop.scala +++ b/src/compiler/scala/tools/nsc/InterpreterLoop.scala @@ -10,6 +10,7 @@ import java.io.{ BufferedReader, File, FileReader, PrintWriter } import java.io.IOException import scala.tools.nsc.{ InterpreterResults => IR } +import scala.collection.JavaConversions.asBuffer import interpreter._ import io.{ Process } @@ -22,30 +23,34 @@ object InterpreterControl { // a single interpreter command sealed abstract class Command extends Function1[List[String], Result] { - val name: String - val help: String + def name: String + def help: String def error(msg: String) = { println(":" + name + " " + msg + ".") Result(true, None) } - def getHelp(): String = ":" + name + " " + help + "." + def usage(): String } case class NoArgs(name: String, help: String, f: () => Result) extends Command { + def usage(): String = ":" + name def apply(args: List[String]) = if (args.isEmpty) f() else error("accepts no arguments") } case class LineArg(name: String, help: String, f: (String) => Result) extends Command { + def usage(): String = ":" + name + " <line>" def apply(args: List[String]) = f(args mkString " ") } case class OneArg(name: String, help: String, f: (String) => Result) extends Command { + def usage(): String = ":" + name + " <arg>" def apply(args: List[String]) = if (args.size == 1) f(args.head) else error("requires exactly one argument") } case class VarArgs(name: String, help: String, f: (List[String]) => Result) extends Command { + def usage(): String = ":" + name + " [arg]" def apply(args: List[String]) = f(args) } @@ -54,8 +59,6 @@ object InterpreterControl { } import InterpreterControl._ -// import scala.concurrent.ops.defaultRunner - /** The * <a href="http://scala-lang.org/" target="_top">Scala</a> * interactive shell. It provides a read-eval-print loop around @@ -76,6 +79,12 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) { /** The input stream from which commands come, set by main() */ var in: InteractiveReader = _ + def history = in match { + case x: JLineReader => Some(x.history) + case _ => None + } + def historyList: Seq[String] = + history map (x => asBuffer(x.getHistoryList): Seq[String]) getOrElse Nil /** The context class loader at the time this object was created */ protected val originalClassLoader = Thread.currentThread.getContextClassLoader @@ -126,8 +135,11 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) { /** print a friendly help message */ def printHelp() = { - out println "All commands can be abbreviated - for example :h or :he instead of :help.\n" - commands foreach { c => out println c.getHelp } + out println "All commands can be abbreviated - for example :he instead of :help.\n" + val cmds = commands map (x => (x.usage, x.help)) + val width: Int = cmds map { case (x, _) => x.length } max + val formatStr = "%-" + width + "s %s" + cmds foreach { case (usage, help) => out println formatStr.format(usage, help) } } /** Print a welcome message */ @@ -143,6 +155,36 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) { out.flush } + /** Show the history */ + def printHistory(xs: List[String]) { + val defaultLines = 20 + + if (history.isEmpty) + return println("No history available.") + + val current = history.get.getCurrentIndex + val count = try xs.head.toInt catch { case _: Exception => defaultLines } + val lines = historyList takeRight count + val offset = current - lines.size + 1 + + for ((line, index) <- lines.zipWithIndex) + println("%d %s".format(index + offset, line)) + } + + /** Search the history */ + def searchHistory(_cmdline: String) { + val cmdline = _cmdline.toLowerCase + + if (history.isEmpty) + return println("No history available.") + + val current = history.get.getCurrentIndex + val offset = current - historyList.size + 1 + + for ((line, index) <- historyList.zipWithIndex ; if line.toLowerCase contains cmdline) + println("%d %s".format(index + offset, line)) + } + /** Prompt to print when awaiting input */ val prompt = Properties.shellPromptString @@ -160,13 +202,15 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) { val standardCommands: List[Command] = { import CommandImplicits._ List( - NoArgs("help", "prints this help message", printHelp), + NoArgs("help", "print this help message", printHelp), + VarArgs("history", "show the history (optional arg: lines to show)", printHistory), + LineArg("h?", "search the history", searchHistory), OneArg("jar", "add a jar to the classpath", addJar), - OneArg("load", "followed by a filename loads a Scala file", load), + OneArg("load", "load and interpret a Scala file", load), NoArgs("power", "enable power user mode", power), - NoArgs("quit", "exits the interpreter", () => Result(false, None)), - NoArgs("replay", "resets execution and replays all previous commands", replay), - LineArg("sh", "forks a shell and runs a command", runShellCmd), + NoArgs("quit", "exit the interpreter", () => Result(false, None)), + NoArgs("replay", "reset execution and replay all previous commands", replay), + LineArg("sh", "fork a shell and run a command", runShellCmd), NoArgs("silent", "disable/enable automatic printing of results", verbosity) ) } @@ -296,9 +340,10 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) { replay() } - def power() = { + def power() { powerUserOn = true interpreter.powerUser() + interpreter.quietBind("history", "scala.collection.immutable.List[String]", historyList.toList) } def verbosity() = { @@ -381,7 +426,7 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) { // the interpeter is passed as an argument to expose tab completion info if (settings.Xnojline.value || emacsShell) new SimpleReader else if (settings.noCompletion.value) InteractiveReader.createDefault() - else InteractiveReader.createDefault(interpreter) + else InteractiveReader.createDefault(interpreter, this) } loadFiles(settings) @@ -399,7 +444,7 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) { // injects one value into the repl; returns pair of name and class def injectOne(name: String, obj: Any): Tuple2[String, String] = { val className = obj.asInstanceOf[AnyRef].getClass.getName - interpreter.bind(name, className, obj) + interpreter.quietBind(name, className, obj) (name, className) } diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala index b039a9e90d..3bd8c98664 100644 --- a/src/compiler/scala/tools/nsc/Settings.scala +++ b/src/compiler/scala/tools/nsc/Settings.scala @@ -399,7 +399,7 @@ object Settings { case None => (outputs filter (isBelow _).tuple) match { case Nil => Nil - case matches => matches.map(_._1.lookupPath(srcPath, false)) + case matches => matches.map(_._1.lookupPathUnchecked(srcPath, false)) } } } diff --git a/src/compiler/scala/tools/nsc/ast/DocComments.scala b/src/compiler/scala/tools/nsc/ast/DocComments.scala index bbd515d40c..a6792b3ba7 100755 --- a/src/compiler/scala/tools/nsc/ast/DocComments.scala +++ b/src/compiler/scala/tools/nsc/ast/DocComments.scala @@ -68,7 +68,7 @@ trait DocComments { self: SymbolTable => /** The list of use cases of doc comment of symbol `sym` seen as a member of class * `site`. Each use case consists of a synthetic symbol (which is entered nowhere else), - * and an expanded doc comment string. + * of an expanded doc comment string, and of its position. * * @param sym The symbol for which use cases are returned * @param site The class for which doc comments are generated @@ -76,16 +76,17 @@ trait DocComments { self: SymbolTable => * of the same string are done, which is * interpreted as a recursive variable definition. */ - def useCases(sym: Symbol, site: Symbol): List[(Symbol, String)] = { + def useCases(sym: Symbol, site: Symbol): List[(Symbol, String, Position)] = { def getUseCases(dc: DocComment) = { for (uc <- dc.useCases; defn <- uc.expandedDefs(site)) yield (defn, - expandVariables(merge(cookedDocComment(sym), uc.comment.raw, defn, copyFirstPara = true), sym, site)) + expandVariables(merge(cookedDocComment(sym), uc.comment.raw, defn, copyFirstPara = true), sym, site), + uc.pos) } getDocComment(sym) map getUseCases getOrElse List() } - def useCases(sym: Symbol): List[(Symbol, String)] = useCases(sym, sym) + def useCases(sym: Symbol): List[(Symbol, String, Position)] = useCases(sym, sym) /** Returns the javadoc format of doc comment string `s`, including wiki expansion */ @@ -357,6 +358,7 @@ trait DocComments { self: SymbolTable => } } val parts = getParts(0) + assert(parts.length > 0, "parts is empty '" + str + "' in site " + site) val partnames = (parts.init map newTermName) ::: List(newTypeName(parts.last)) val (start, rest) = if (parts.head == "this") @@ -375,7 +377,7 @@ trait DocComments { self: SymbolTable => for (alias <- aliases) yield lookupVariable(alias.name.toString.substring(1), site) match { case Some(repl) => - val tpe = getType(repl) + val tpe = getType(repl.trim) if (tpe != NoType) tpe else { val alias1 = alias.cloneSymbol(definitions.RootClass) @@ -406,7 +408,7 @@ trait DocComments { self: SymbolTable => } for (defn <- defined) yield { - defn.cloneSymbol(site).setInfo( + defn.cloneSymbol(site).setFlag(Flags.SYNTHETIC).setInfo( substAliases(defn.info).asSeenFrom(site.thisType, defn.owner)) } } diff --git a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala index bd46d2219d..1f17f148aa 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala @@ -36,6 +36,9 @@ trait MarkupParsers { self: Parsers => + type PositionType = Position + type InputType = CharArrayReader + case object MissingEndTagException extends RuntimeException with ControlException { override def getMessage = "start tag was here: " } @@ -62,6 +65,8 @@ trait MarkupParsers else reportSyntaxError(msg) var input : CharArrayReader = _ + def lookahead(): BufferedIterator[Char] = + (input.buf drop input.charOffset).iterator.buffered import parser.{ symbXMLBuilder => handle, o2p, r2p } @@ -83,7 +88,6 @@ trait MarkupParsers private var debugLastStartElement = new mutable.Stack[(Int, String)] private def debugLastPos = debugLastStartElement.top._1 private def debugLastElem = debugLastStartElement.top._2 - private def unreachable = Predef.error("Cannot be reached.") private def errorBraces() = { reportSyntaxError("in XML content, please use '}}' to express '}'") @@ -190,55 +194,13 @@ trait MarkupParsers xToken('>') } - /** Create a non-destructive lookahead reader and see if the head - * of the input would match the given String. If yes, return true - * and drop the entire String from input; if no, return false - * and leave input unchanged. - */ - private def peek(lookingFor: String): Boolean = { - val la = input.lookaheadReader - for (c <- lookingFor) { - la.nextChar() - if (la.ch != c) - return false - } - // drop the chars from the real reader (all lookahead + orig) - (0 to lookingFor.length) foreach (_ => nextch) - true - } - - /** Take characters from input stream until given String "until" - * is seen. Once seen, the accumulated characters are passed - * along with the current Position to the supplied handler function. - */ - private def xTakeUntil[T]( - handler: (Position, String) => T, - positioner: () => Position, - until: String): T = - { - val sb = new StringBuilder - val head = until charAt 0 - val rest = until drop 1 - - while (true) { - if (ch == head && peek(rest)) - return handler(positioner(), sb.toString) - else if (ch == SU) - throw TruncatedXML - - sb append ch - nextch - } - unreachable - } - /** '<! CharData ::= [CDATA[ ( {char} - {char}"]]>"{char} ) ']]>' * * see [15] */ def xCharData: Tree = { val start = curOffset - "[CDATA[" foreach xToken + xToken("[CDATA[") val mid = curOffset xTakeUntil(handle.charData, () => r2p(start, mid, curOffset), "]]>") } @@ -284,7 +246,7 @@ trait MarkupParsers */ def xComment: Tree = { val start = curOffset - 2 // Rewinding to include "<!" - "--" foreach xToken + xToken("--") xTakeUntil(handle.comment, () => r2p(start, start, curOffset), "-->") } @@ -374,7 +336,7 @@ trait MarkupParsers val start = curOffset val (qname, attrMap) = xTag if (ch == '/') { // empty element - "/>" foreach xToken + xToken("/>") handle.element(r2p(start, start, curOffset), qname, attrMap, new ListBuffer[Tree]) } else { // handle content diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index a89f4f01c3..b86356ba94 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -421,14 +421,19 @@ self => def joinComment(trees: => List[Tree]): List[Tree] = { val doc = in.flushDoc if ((doc ne null) && doc.raw.length > 0) { - val ts = trees - val main = ts.find(_.pos.isOpaqueRange) - ts map { + val joined = trees map { t => val dd = DocDef(doc, t) - val pos = doc.pos.withEnd(t.pos.endOrPoint) - dd setPos (if (t eq main) pos else pos.makeTransparent) + val defnPos = t.pos + val pos = doc.pos.withEnd(defnPos.endOrPoint) + dd setPos (if (defnPos.isOpaqueRange) pos else pos.makeTransparent) } + joined.find(_.pos.isOpaqueRange) foreach { + main => + val mains = List(main) + joined foreach { t => if (t ne main) ensureNonOverlapping(t, mains) } + } + joined } else trees } @@ -2460,14 +2465,15 @@ self => val stats = new ListBuffer[Tree] while (in.token != RBRACE && in.token != EOF) { if (in.token == PACKAGE) { + in.flushDoc val start = in.skipToken() stats += { if (in.token == OBJECT) makePackageObject(start, objectDef(in.offset, NoMods)) else packaging(start) } } else if (in.token == IMPORT) { + in.flushDoc stats ++= importClause() - // XXX: IDE hook this all. } else if (in.token == CLASS || in.token == CASECLASS || in.token == TRAIT || @@ -2498,6 +2504,7 @@ self => var self: ValDef = emptyValDef val stats = new ListBuffer[Tree] if (isExprIntro) { + in.flushDoc val first = expr(InTemplate) // @S: first statement is potentially converted so cannot be stubbed. if (in.token == ARROW) { first match { @@ -2518,8 +2525,10 @@ self => } while (in.token != RBRACE && in.token != EOF) { if (in.token == IMPORT) { + in.flushDoc stats ++= importClause() } else if (isExprIntro) { + in.flushDoc stats += statement(InTemplate) } else if (isDefIntro || isModifier || in.token == LBRACKET /*todo: remove */ || in.token == AT) { stats ++= joinComment(nonLocalDefOrDcl) @@ -2618,6 +2627,7 @@ self => while (in.token == SEMI) in.nextToken() val start = in.offset if (in.token == PACKAGE) { + in.flushDoc in.nextToken() if (in.token == OBJECT) { ts += makePackageObject(start, objectDef(in.offset, NoMods)) @@ -2645,10 +2655,14 @@ self => } ts.toList } - val start = caseAwareTokenOffset max 0 topstats() match { case List(stat @ PackageDef(_, _)) => stat - case stats => makePackaging(start, atPos(o2p(start)) { Ident(nme.EMPTY_PACKAGE_NAME) }, stats) + case stats => + val start = stats match { + case Nil => 0 + case _ => wrappingPos(stats).startOrPoint + } + makePackaging(start, atPos(start, start, start) { Ident(nme.EMPTY_PACKAGE_NAME) }, stats) } } } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index be90a835f5..6cb7c8b99f 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -166,6 +166,11 @@ trait Scanners { sepRegions = sepRegions.tail case _ => } + (lastToken: @switch) match { + case RBRACE | RBRACKET | RPAREN => + docBuffer = null + case _ => + } // Read a token or copy it from `next` tokenData if (next.token == EMPTY) { diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index cd690097e8..2f66f672d8 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -362,7 +362,7 @@ abstract class GenICode extends SubComponent { thenCtx = genLoad(thenp, thenCtx, resKind) elseCtx = genLoad(elsep, elseCtx, resKind) - assert(!settings.debug.value || expectedType == UNIT, + assert(!settings.debug.value || !(hasUnitBranch && expectedType != UNIT), "I produce UNIT in a context where " + expectedType + " is expected!") thenCtx.bb.emitOnly(JUMP(contCtx.bb)) @@ -1410,7 +1410,14 @@ abstract class GenICode extends SubComponent { assert(ctx.clazz.symbol eq cls, "Classes are not the same: " + ctx.clazz.symbol + ", " + cls) - for (f <- cls.info.decls ; if !f.isMethod && f.isTerm) + /** Non-method term members are fields, except for moudle members. Module + * members can only happen on .NET (no flatten) for inner traits. There, + * a module symbol is generated (transformInfo in mixin) which is used + * as owner for the members of the implementation class (so that the + * backend emits them as static). + * No code is needed for this module symbol. + */ + for (f <- cls.info.decls ; if !f.isMethod && f.isTerm && !f.isModule) ctx.clazz addField new IField(f) } diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala index 4f0da17bb3..8a65875fbf 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala @@ -146,10 +146,12 @@ abstract class CopyPropagation { target match { case Deref(LocalVar(l)) => val alias = getAlias(l) + val derefAlias = Deref(LocalVar(alias)) getBinding(alias) match { - case Record(_, _) => Some(Deref(LocalVar(alias))) + case Record(_, _) => Some(derefAlias) case Deref(Field(r1, f1)) => - getFieldNonRecordValue(r1, f1) orElse Some(Deref(LocalVar(alias))) + getFieldNonRecordValue(r1, f1) orElse Some(derefAlias) + case Boxed(_) => Some(derefAlias) case v => Some(v) } case Deref(Field(r1, f1)) => diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index 4c9a996cec..016e70a968 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -315,7 +315,7 @@ abstract class Inliners extends SubComponent { i match { case CALL_METHOD(msym, Dynamic) => def warnNoInline(reason: String) = { - if (msym.hasAnnotation(ScalaInlineAttr)) + if (msym.hasAnnotation(ScalaInlineAttr) && !m.symbol.hasFlag(Flags.BRIDGE)) currentIClazz.cunit.warning(i.pos, "Could not inline required method %s because %s.".format(msym.originalName.decode, reason)) } diff --git a/src/compiler/scala/tools/nsc/dependencies/Changes.scala b/src/compiler/scala/tools/nsc/dependencies/Changes.scala index 87e38d8909..43efd0726b 100644 --- a/src/compiler/scala/tools/nsc/dependencies/Changes.scala +++ b/src/compiler/scala/tools/nsc/dependencies/Changes.scala @@ -92,7 +92,7 @@ abstract class Changes { // new dependent types: probably fix this, use substSym as done for PolyType (sameTypes(tp1.paramTypes, tp2.paramTypes) && ((tp1.params, tp2.params).zipped forall ((t1, t2) => - (sameSymbol(t1, t1) && sameFlags(t1, t2)))) && + (sameSymbol(t1, t2) && sameFlags(t1, t2)))) && sameType(res1, res2) && tp1.isInstanceOf[ImplicitMethodType] == tp2.isInstanceOf[ImplicitMethodType]) @@ -101,7 +101,7 @@ abstract class Changes { case (ExistentialType(tparams1, res1), ExistentialType(tparams2, res2)) => sameTypeParams(tparams1, tparams2) && sameType(res1, res2) case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) => - sameType(lo1, lo2) && sameType(hi1, hi2) + sameType(lo1, lo2) && sameType(hi1, hi2) case (BoundedWildcardType(bounds), _) => bounds containsType tp2 case (_, BoundedWildcardType(bounds)) => @@ -133,40 +133,46 @@ abstract class Changes { } private def sameTypeParams(tparams1: List[Symbol], tparams2: List[Symbol]) = - sameTypes(tparams1 map (_.info), tparams2 map (_.info)) + sameTypes(tparams1 map (_.info), tparams2 map (_.info)) && + sameTypes(tparams1 map (_.tpe), tparams2 map (_.tpe)) def sameTypes(tps1: List[Type], tps2: List[Type]): Boolean = (tps1.length == tps2.length) && ((tps1, tps2).zipped forall sameType) - /** Return the list of changes between 'from' and 'to'. + /** Return the list of changes between 'from' and 'toSym.info'. */ - def changeSet(from: Symbol, to: Symbol): List[Change] = { + def changeSet(from: Type, toSym: Symbol): List[Change] = { implicit val defaultReason = "types" -// println("changeSet " + from + "(" + from.info + ")" -// + " vs " + to + "(" + to.info + ")") + val to = toSym.info def omitSymbols(s: Symbol): Boolean = !s.hasFlag(LOCAL | LIFTED | PRIVATE) val cs = new mutable.ListBuffer[Change] - if ((from.info.parents zip to.info.parents) exists { case (t1, t2) => !sameType(t1, t2) }) - cs += Changed(toEntity(from))(from.info.parents.zip(to.info.parents).toString) - if (from.typeParams != to.typeParams) - cs += Changed(toEntity(from))(" tparams: " + from.typeParams.zip(to.typeParams)) + if ((from.parents zip to.parents) exists { case (t1, t2) => !sameType(t1, t2) }) + cs += Changed(toEntity(toSym))(from.parents.zip(to.parents).toString) + if (!sameTypeParams(from.typeParams, to.typeParams)) + cs += Changed(toEntity(toSym))(" tparams: " + from.typeParams.zip(to.typeParams)) // new members not yet visited val newMembers = mutable.HashSet[Symbol]() - newMembers ++= to.info.decls.iterator filter omitSymbols + newMembers ++= to.decls.iterator filter omitSymbols - for (o <- from.info.decls.iterator filter omitSymbols) { - val n = to.info.decl(o.name) + for (o <- from.decls.iterator filter omitSymbols) { + val n = to.decl(o.name) newMembers -= n if (o.isClass) - cs ++= changeSet(o, n) + cs ++= changeSet(o.info, n) else if (n == NoSymbol) cs += Removed(toEntity(o)) else { - val newSym = n.suchThat(ov => sameType(ov.tpe, o.tpe)) + val newSym = + o match { + case _:TypeSymbol if o.isAliasType => + n.suchThat(ov => sameType(ov.info, o.info)) + case _ => + n.suchThat(ov => sameType(ov.tpe, o.tpe)) + } if (newSym == NoSymbol || moreRestrictive(o.flags, newSym.flags)) cs += Changed(toEntity(o))(n + " changed from " + o.tpe + " to " + n.tpe + " flags: " + Flags.flagsToString(o.flags)) else diff --git a/src/compiler/scala/tools/nsc/doc/DocFactory.scala b/src/compiler/scala/tools/nsc/doc/DocFactory.scala index 99cec01949..b70d8c10ec 100644 --- a/src/compiler/scala/tools/nsc/doc/DocFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/DocFactory.scala @@ -12,10 +12,10 @@ import reporters.Reporter * * A simplified compiler instance (with only the front-end phases enabled) is created, and additional * ''sourceless'' comments are registered. * * Documentable files are compiled, thereby filling the compiler's symbol table. - * * A documentation model is extracted from the post-compilation compiler's symbol table. + * * A documentation model is extracted from the post-compilation symbol table. * * A generator is used to transform the model into the correct final format (HTML). * - * A processor contains a single compiler instantiated from the processor's settings. Each call to the `run` method + * A processor contains a single compiler instantiated from the processor's `settings`. Each call to `document` * uses the same compiler instance with the same symbol table. In particular, this implies that the scaladoc site * obtained from a call to `run` will contain documentation about files compiled during previous calls to the same * processor's `run` method. @@ -50,6 +50,7 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor def document(files: List[String]): Unit = { (new compiler.Run()) compile files compiler.addSourceless + assert(settings.docformat.value == "html") if (!reporter.hasErrors) { val modelFactory = (new model.ModelFactory(compiler, settings)) val htmlFactory = (new html.HtmlFactory(reporter, settings)) diff --git a/src/compiler/scala/tools/nsc/doc/DocProvider.scala b/src/compiler/scala/tools/nsc/doc/DocProvider.scala new file mode 100644 index 0000000000..bcf227ebb9 --- /dev/null +++ b/src/compiler/scala/tools/nsc/doc/DocProvider.scala @@ -0,0 +1,3 @@ +package scala.tools.nsc.doc + +class DocProvider
\ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/doc/SourcelessComments.scala b/src/compiler/scala/tools/nsc/doc/SourcelessComments.scala index 9216fa6f23..0791c6fa51 100644 --- a/src/compiler/scala/tools/nsc/doc/SourcelessComments.scala +++ b/src/compiler/scala/tools/nsc/doc/SourcelessComments.scala @@ -6,12 +6,11 @@ package doc import scala.collection._ /** - * This class contains comments to all symbols which pre-exist in Scala, such as Any, Nothing, ... - * It also contains a HashSet of the given symbols - * The comments are to be added to a HashMap called comments, which resides in the Global.scala file - * @author Manohar Jonnalagedda, Stephane Micheloud, Sean McDirmid, Geoffrey Washburn - * @version 1.0 - */ + * A class that provides comments for all symbols which pre-exist in Scala (Any, Nothing, ...) + * It also contains a HashSet of the given symbols + * The comments are to be added to a HashMap called comments, which resides in the Global.scala file + * @author Manohar Jonnalagedda, Stephane Micheloud, Sean McDirmid, Geoffrey Washburn + * @version 1.0 */ abstract class SourcelessComments { val global: Global diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala index 4ffdba4603..119823ff13 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala @@ -100,15 +100,22 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage { </li> } - def memberToCommentHtml(mbr: MemberEntity, isSelf: Boolean): NodeSeq = mbr match { - case dte: DocTemplateEntity if isSelf => - <div id="comment" class="fullcomment">{ memberToFullCommentHtml(mbr, isSelf) }</div> - case dte: DocTemplateEntity if mbr.comment.isDefined => - <p class="comment cmt">{ inlineToHtml(mbr.comment.get.short) }</p> - case _ if mbr.comment.isDefined => - <p class="shortcomment cmt">{ inlineToHtml(mbr.comment.get.short) }</p> - <div class="fullcomment">{ memberToFullCommentHtml(mbr, isSelf) }</div> - case _ => NodeSeq.Empty + def memberToCommentHtml(mbr: MemberEntity, isSelf: Boolean): NodeSeq = { + val useCaseCommentHtml = mbr match { + case nte: NonTemplateMemberEntity if nte.isUseCase => + inlineToHtml(comment.Text("[use case] ")) + case _ => NodeSeq.Empty + } + mbr match { + case dte: DocTemplateEntity if isSelf => + <div id="comment" class="fullcomment">{ memberToFullCommentHtml(mbr, isSelf) }</div> + case dte: DocTemplateEntity if mbr.comment.isDefined => + <p class="comment cmt">{ inlineToHtml(mbr.comment.get.short) }</p> + case _ if mbr.comment.isDefined => + <p class="shortcomment cmt">{ useCaseCommentHtml }{ inlineToHtml(mbr.comment.get.short) }</p> + <div class="fullcomment">{ useCaseCommentHtml }{ memberToFullCommentHtml(mbr, isSelf) }</div> + case _ => useCaseCommentHtml + } } def memberToFullCommentHtml(mbr: MemberEntity, isSelf: Boolean): NodeSeq = @@ -178,6 +185,15 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage { case _ => NodeSeq.Empty } } + { tpl.companion match { + case Some(companion) => + <div class="block"> + Go to: <a href={relativeLinkTo(companion)}>companion</a> + </div> + case None => + NodeSeq.Empty + } + } </xml:group> def kindToString(mbr: MemberEntity): String = mbr match { diff --git a/src/compiler/scala/tools/nsc/doc/model/Entity.scala b/src/compiler/scala/tools/nsc/doc/model/Entity.scala index 3e61b7f4ee..d7ef2b866d 100644 --- a/src/compiler/scala/tools/nsc/doc/model/Entity.scala +++ b/src/compiler/scala/tools/nsc/doc/model/Entity.scala @@ -70,6 +70,7 @@ trait DocTemplateEntity extends TemplateEntity with MemberEntity { def values: List[Val] def abstractTypes: List[AbstractType] def aliasTypes: List[AliasType] + def companion: Option[DocTemplateEntity] } /** A ''documentable'' trait. */ @@ -94,7 +95,9 @@ trait Package extends Object { def packages: List[Package] } -trait NonTemplateMemberEntity extends MemberEntity +trait NonTemplateMemberEntity extends MemberEntity { + def isUseCase: Boolean +} /** A method (`def`) of a ''documentable'' class, trait or object. */ trait Def extends NonTemplateMemberEntity { diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index 0817cec4e2..f935dd4478 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -7,7 +7,9 @@ package model import comment._ import scala.collection._ + import symtab.Flags +import util.Position /** This trait extracts all required information for documentation from compilation units */ class ModelFactory(val global: Global, val settings: doc.Settings) { extractor => @@ -22,21 +24,45 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { extractor = def makeModel: Package = makePackage(RootPackage, null) getOrElse { throw new Error("no documentable class found in compilation units") } - /** */ - protected val commentFactory = new CommentFactory(reporter) + object commentator { - /** */ - protected val commentCache = mutable.Map.empty[Symbol, comment.Comment] + private val factory = new CommentFactory(reporter) + + private val commentCache = mutable.HashMap.empty[(Symbol, TemplateImpl), Comment] + + def registeredUseCase(sym: Symbol, inTpl: => TemplateImpl, docStr: String, docPos: Position): Symbol = { + commentCache += (sym, inTpl) -> factory.parse(docStr, docPos) + sym + } + + def comment(sym: Symbol, inTpl: => DocTemplateImpl): Option[Comment] = { + val key = (sym, inTpl) + if (commentCache isDefinedAt key) + Some(commentCache(key)) + else { // not reached for use-case comments + val rawComment = expandedDocComment(sym, inTpl.sym) + if (rawComment == "") None else { + val c = factory.parse(rawComment, docCommentPos(sym)) + commentCache += (sym, inTpl) -> c + Some(c) + } + } + } + + } /** */ protected val templatesCache = new mutable.LinkedHashMap[(Symbol, TemplateImpl), DocTemplateImpl] + def optimize(str: String): String = + if (str.length < 16) str.intern else str + /* ============== IMPLEMENTATION PROVIDING ENTITY TYPES ============== */ /** Provides a default implementation for instances of the `Entity` type. */ abstract class EntityImpl(val sym: Symbol, inTpl: => TemplateImpl) extends Entity { - val name = sym.nameString + val name = optimize(sym.nameString) def inTemplate = inTpl def toRoot: List[EntityImpl] = this :: inTpl.toRoot def qualifiedName = name @@ -45,12 +71,12 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { extractor = /** Provides a default implementation for instances of the `WeakTemplateEntity` type. It must be instantiated as a * `SymbolicEntity` to access the compiler symbol that underlies the entity. */ trait TemplateImpl extends EntityImpl with TemplateEntity { - override def qualifiedName = if (inTemplate.isRootPackage) name else (inTemplate.qualifiedName + "." + name) - val isPackage = sym.isPackage - val isTrait = sym.isTrait - val isClass = sym.isClass && !sym.isTrait - val isObject = sym.isModule && !sym.isPackage - val isRootPackage = false + override def qualifiedName = if (inTemplate.isRootPackage) name else optimize(inTemplate.qualifiedName + "." + name) + def isPackage = sym.isPackage + def isTrait = sym.isTrait + def isClass = sym.isClass && !sym.isTrait + def isObject = sym.isModule && !sym.isPackage + def isRootPackage = false } /** Provides a default implementation for instances of the `WeakTemplateEntity` type. It must be instantiated as a @@ -63,14 +89,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { extractor = * `SymbolicEntity` to access the compiler symbol that underlies the entity. */ abstract class MemberImpl(sym: Symbol, inTpl: => DocTemplateImpl) extends EntityImpl(sym, inTpl) with MemberEntity { val comment = - if (inTpl == null) None else { - val rawComment = expandedDocComment(sym, inTpl.sym) - if (rawComment == "") None else { - val c = commentFactory.parse(rawComment, docCommentPos(sym)) - commentCache += sym -> c - Some(c) - } - } + if (inTpl == null) None else commentator.comment(sym, inTpl) override def inTemplate = inTpl override def toRoot: List[MemberImpl] = this :: inTpl.toRoot def inDefinitionTemplates = @@ -80,7 +99,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { extractor = inTpl :: Nil else makeTemplate(sym.owner) :: (sym.allOverriddenSymbols map { inhSym => makeTemplate(inhSym.owner) }) - val visibility = { + def visibility = { def qual = { val qq = if (sym hasFlag Flags.LOCAL) @@ -90,11 +109,11 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { extractor = else None qq match { case Some(q) => "[" + q + "]" case None => "" } } - if (sym hasFlag Flags.PRIVATE) Some(Paragraph(Text("private" + qual))) - else if (sym hasFlag Flags.PROTECTED) Some(Paragraph(Text("protected" + qual))) + if (sym hasFlag Flags.PRIVATE) Some(Paragraph(Text(optimize("private" + qual)))) + else if (sym hasFlag Flags.PROTECTED) Some(Paragraph(Text(optimize("protected" + qual)))) else None } - val flags = { + def flags = { val fgs = mutable.ListBuffer.empty[Paragraph] if (sym hasFlag Flags.IMPLICIT) fgs += Paragraph(Text("implicit")) if (sym hasFlag Flags.SEALED) fgs += Paragraph(Text("sealed")) @@ -103,18 +122,18 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { extractor = if (!sym.isModule && (sym hasFlag Flags.FINAL)) fgs += Paragraph(Text("final")) fgs.toList } - lazy val inheritedFrom = + def inheritedFrom = if (inTemplate.sym == this.sym.owner || inTemplate.sym.isPackage) Nil else makeTemplate(this.sym.owner) :: (sym.allOverriddenSymbols map { os => makeTemplate(os.owner) }) - val isDeprecated = sym.isDeprecated - lazy val resultType = makeType(sym.tpe.finalResultType, inTemplate, sym) - val isDef = false - val isVal = false - val isVar = false - val isConstructor = false - val isAliasType = false - val isAbstractType = false - val isTemplate = false + def isDeprecated = sym.isDeprecated + def resultType = makeType(sym.tpe.finalResultType, inTemplate, sym) + def isDef = false + def isVal = false + def isVar = false + def isConstructor = false + def isAliasType = false + def isAbstractType = false + def isTemplate = false } /** Provides a default implementation for instances of the `TemplateEntity` type. It must be instantiated as a @@ -128,11 +147,11 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { extractor = abstract class DocTemplateImpl(sym: Symbol, inTpl: => DocTemplateImpl) extends MemberImpl(sym, inTpl) with TemplateImpl with DocTemplateEntity { //if (inTpl != null) println("mbr " + sym + " in " + (inTpl.toRoot map (_.sym)).mkString(" > ")) templatesCache += ((sym, inTpl) -> this) - override def definitionName = inDefinitionTemplates.head.qualifiedName + "." + name + override def definitionName = optimize(inDefinitionTemplates.head.qualifiedName + "." + name) override def toRoot: List[DocTemplateImpl] = this :: inTpl.toRoot - val inSource = if (sym.sourceFile != null) Some(sym.sourceFile, sym.pos.line) else None - val typeParams = if (sym.isClass) sym.typeParams map (makeTypeParam(_, this)) else Nil - val parentType = + def inSource = if (sym.sourceFile != null) Some(sym.sourceFile, sym.pos.line) else None + def typeParams = if (sym.isClass) sym.typeParams map (makeTypeParam(_, this)) else Nil + def parentType = if (sym.isPackage) None else Some(makeType(RefinedType(sym.tpe.parents filter (_ != ScalaObjectClass.tpe), EmptyScope))) val linearization = { @@ -150,15 +169,19 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { extractor = subClassesCache += sc } def subClasses = subClassesCache.toList - def memberSyms = sym.info.nonPrivateMembers + protected def memberSyms = sym.info.nonPrivateMembers val members: List[MemberEntity] = memberSyms flatMap (makeMember(_, this)) val templates = members partialMap { case c: DocTemplateEntity => c } val methods = members partialMap { case d: Def => d } val values = members partialMap { case v: Val => v } val abstractTypes = members partialMap { case t: AbstractType => t } val aliasTypes = members partialMap { case t: AliasType => t } - override val isTemplate = true + override def isTemplate = true def isDocTemplate = true + def companion = sym.linkedSym match { + case NoSymbol => None + case comSym => Some(makeDocTemplate(comSym, inTpl)) + } } abstract class PackageImpl(sym: Symbol, inTpl: => PackageImpl) extends DocTemplateImpl(sym, inTpl) with Package { @@ -168,8 +191,8 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { extractor = } abstract class NonTemplateMemberImpl(sym: Symbol, inTpl: => DocTemplateImpl) extends MemberImpl(sym, inTpl) with NonTemplateMemberEntity { - override def qualifiedName = inTemplate.qualifiedName + "#" + name - override def definitionName = inDefinitionTemplates.head.qualifiedName + "#" + name + override def qualifiedName = optimize(inTemplate.qualifiedName + "#" + name) + override def definitionName = optimize(inDefinitionTemplates.head.qualifiedName + "#" + name) } abstract class ParameterImpl(sym: Symbol, inTpl: => DocTemplateImpl) extends EntityImpl(sym, inTpl) with ParameterEntity { @@ -204,9 +227,9 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { extractor = override def inTemplate = this override def toRoot = this :: Nil override def qualifiedName = "_root_" - override lazy val inheritedFrom = Nil - override val isRootPackage = true - override def memberSyms = + override def inheritedFrom = Nil + override def isRootPackage = true + override protected def memberSyms = (bSym.info.members ++ EmptyPackage.info.members) filter { s => s != EmptyPackage && s != RootPackage } @@ -262,95 +285,109 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { extractor = new DocTemplateImpl(bSym, firstInTpl) with Object else if (bSym.isTrait || (bSym.isAliasType && bSym.tpe.typeSymbol.isTrait)) new DocTemplateImpl(bSym, firstInTpl) with Trait { - val valueParams = + def valueParams = List(sym.constrParamAccessors map (makeValueParam(_, this))) } else if (bSym.isClass || (bSym.isAliasType && bSym.tpe.typeSymbol.isClass)) new DocTemplateImpl(bSym, firstInTpl) with Class { - val valueParams = + def valueParams = List(sym.constrParamAccessors map (makeValueParam(_, this))) val constructors = members partialMap { case d: Constructor => d } - val primaryConstructor = (constructors find (_.isPrimary)) - val isCaseClass = sym.isClass && sym.hasFlag(Flags.CASE) + def primaryConstructor = (constructors find (_.isPrimary)) + def isCaseClass = sym.isClass && sym.hasFlag(Flags.CASE) } else throw new Error("'" + bSym + "' that isn't a class, trait or object cannot be built as a documentable template") } /** */ - def makeMember(aSym: Symbol, inTpl: => DocTemplateImpl): Option[MemberImpl] = { + def makeMember(aSym: Symbol, inTpl: => DocTemplateImpl): List[MemberImpl] = { + def makeMember0(bSym: Symbol): Option[MemberImpl] = { + if (bSym.isGetter && (bSym.accessed hasFlag Flags.MUTABLE)) + Some(new NonTemplateMemberImpl(bSym, inTpl) with Val { + override def isVar = true + def isUseCase = bSym hasFlag Flags.SYNTHETIC + }) + else if (bSym.isMethod && !(bSym hasFlag Flags.ACCESSOR) && !bSym.isConstructor && !(bSym hasFlag Flags.FINAL)) + Some(new NonTemplateMemberImpl(bSym, inTpl) with Def { + override def isDef = true + def isUseCase = bSym hasFlag Flags.SYNTHETIC + def typeParams = + sym.tpe.typeParams map (makeTypeParam(_, inTpl)) + def valueParams = + sym.paramss map { ps => (ps.zipWithIndex) map { case (p, i) => + if (p.nameString contains "$") makeValueParam(p, inTpl, optimize("arg" + i)) else makeValueParam(p, inTpl) + }} + }) + else if (bSym.isConstructor) + Some(new NonTemplateMemberImpl(bSym, inTpl) with Constructor { + override def isConstructor = true + def isUseCase = bSym hasFlag Flags.SYNTHETIC + def isPrimary = sym.isPrimaryConstructor + def valueParams = + sym.paramss map { ps => (ps.zipWithIndex) map { case (p, i) => + if (p.nameString contains "$") makeValueParam(p, inTpl, optimize("arg" + i)) else makeValueParam(p, inTpl) + }} + }) + else if (bSym.isGetter) // Scala field accessor or Java field + Some(new NonTemplateMemberImpl(bSym, inTpl) with Val { + override def isVal = true + def isUseCase = bSym hasFlag Flags.SYNTHETIC + }) + else if (bSym.isAbstractType) + Some(new NonTemplateMemberImpl(bSym, inTpl) with AbstractType { + override def isAbstractType = true + def isUseCase = bSym hasFlag Flags.SYNTHETIC + def lo = sym.info.normalize match { + case TypeBounds(lo, hi) if lo.typeSymbol != definitions.NothingClass => Some(makeType(lo, inTpl, sym)) + case _ => None + } + def hi = sym.info.normalize match { + case TypeBounds(lo, hi) if hi.typeSymbol != definitions.AnyClass => Some(makeType(hi, inTpl, sym)) + case _ => None + } + }) + else if (bSym.isAliasType) + Some(new NonTemplateMemberImpl(bSym, inTpl) with AliasType { + override def isAliasType = true + def isUseCase = bSym hasFlag Flags.SYNTHETIC + def alias = makeType(sym.tpe, inTpl, sym) + }) + else if (bSym.isPackage) + inTpl match { case inPkg: PackageImpl => makePackage(bSym, inPkg) } + else if ((bSym.isClass || bSym.isModule) && (bSym.sourceFile != null) && bSym.isPublic && !bSym.isLocal) { + (inTpl.toRoot find (_.sym == bSym )) orElse Some(makeDocTemplate(bSym, inTpl)) + } + else + None + } if (!aSym.isPublic || (aSym hasFlag Flags.SYNTHETIC) || (aSym hasFlag Flags.BRIDGE) || aSym.isLocal || aSym.isModuleClass || aSym.isPackageObject || aSym.isMixinConstructor) - None - else if (aSym.isGetter && (aSym.accessed hasFlag Flags.MUTABLE)) - Some(new NonTemplateMemberImpl(aSym, inTpl) with Val { - override val isVar = true - }) - else if (aSym.isMethod && !(aSym hasFlag Flags.ACCESSOR) && !aSym.isConstructor && !(aSym hasFlag Flags.FINAL)) - Some(new NonTemplateMemberImpl(aSym, inTpl) with Def { - override val isDef = true - val typeParams = - sym.tpe.typeParams map (makeTypeParam(_, inTpl)) - val valueParams = - sym.paramss map { ps => (ps.zipWithIndex) map { case (p, i) => - if (p.nameString contains "$") makeValueParam(p, inTpl, "arg" + i) else makeValueParam(p, inTpl) - }} - }) - else if (aSym.isConstructor) - Some(new NonTemplateMemberImpl(aSym, inTpl) with Constructor { - override val isConstructor = true - val isPrimary = sym.isPrimaryConstructor - val valueParams = - sym.paramss map { ps => (ps.zipWithIndex) map { case (p, i) => - if (p.nameString contains "$") makeValueParam(p, inTpl, "arg" + i) else makeValueParam(p, inTpl) - }} - }) - else if (aSym.isGetter) // Scala field accessor or Java field - Some(new NonTemplateMemberImpl(aSym, inTpl) with Val { - override val isVal = true - }) - else if (aSym.isAbstractType) - Some(new NonTemplateMemberImpl(aSym, inTpl) with AbstractType { - override val isAbstractType = true - val lo = sym.info.normalize match { - case TypeBounds(lo, hi) if lo.typeSymbol != definitions.NothingClass => Some(makeType(lo, inTpl, sym)) - case _ => None - } - val hi = sym.info.normalize match { - case TypeBounds(lo, hi) if hi.typeSymbol != definitions.AnyClass => Some(makeType(hi, inTpl, sym)) - case _ => None - } - }) - else if (aSym.isAliasType) - Some(new NonTemplateMemberImpl(aSym, inTpl) with AliasType { - override val isAliasType = true - val alias = makeType(sym.tpe, inTpl, sym) - }) - else if (aSym.isPackage) - inTpl match { case inPkg: PackageImpl => makePackage(aSym, inPkg) } - else if ((aSym.isClass || aSym.isModule) && (aSym.sourceFile != null) && aSym.isPublic && !aSym.isLocal) { - (inTpl.toRoot find (_.sym == aSym )) orElse Some(makeDocTemplate(aSym, inTpl)) + Nil + else { + val allSyms = useCases(aSym, inTpl.sym) map { case (bSym, bComment, bPos) => + commentator.registeredUseCase(bSym, inTpl, bComment, bPos) + } + (allSyms ::: List(aSym)) flatMap (makeMember0(_)) } - else - None } /** */ def makeTypeParam(aSym: Symbol, inTpl: => DocTemplateImpl): TypeParam = { new ParameterImpl(aSym, inTpl) with TypeParam { - val isTypeParam = true - val isValueParam = false - val variance: String = { + def isTypeParam = true + def isValueParam = false + def variance: String = { if (sym hasFlag Flags.COVARIANT) "+" else if (sym hasFlag Flags.CONTRAVARIANT) "-" else "" } - val lo = sym.info.normalize match { + def lo = sym.info.normalize match { case TypeBounds(lo, hi) if lo.typeSymbol != definitions.NothingClass => Some(makeType(lo, inTpl, sym)) case _ => None } - val hi = sym.info.normalize match { + def hi = sym.info.normalize match { case TypeBounds(lo, hi) if hi.typeSymbol != definitions.AnyClass => Some(makeType(hi, inTpl, sym)) case _ => None @@ -366,12 +403,12 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { extractor = /** */ def makeValueParam(aSym: Symbol, inTpl: => DocTemplateImpl, newName: String): ValueParam = { new ParameterImpl(aSym, inTpl) with ValueParam { - val isTypeParam = false - val isValueParam = true - val resultType = { + override val name = newName + def isTypeParam = false + def isValueParam = true + def resultType = { makeType(sym.tpe, inTpl, sym) } - override val name = newName } } @@ -449,7 +486,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { extractor = } appendType0(aType) val refEntity = refBuffer - val name = nameBuffer.toString + val name = optimize(nameBuffer.toString) } } diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala index d51573364f..4504a97af5 100644 --- a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala @@ -495,7 +495,7 @@ final class CommentFactory(val reporter: Reporter) { parser => final def getRead(): String = { val bld = readBuilder.toString readBuilder.clear() - bld + if (bld.length < 6) bld.intern else bld } final def readUntil(ch: Char): Int = { diff --git a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala b/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala index 5414b53e0c..9ca9a740df 100644 --- a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala +++ b/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala @@ -40,15 +40,15 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana protected def newCompiler(settings: Settings) = new BuilderGlobal(settings) val compiler = newCompiler(settings) - import compiler.{Symbol, atPhase, currentRun} + import compiler.{Symbol, Type, atPhase, currentRun} - private case class Symbols(sym: Symbol, symBefErasure: Symbol) + private case class SymWithHistory(sym: Symbol, befErasure: Type) /** Managed source files. */ private val sources: mutable.Set[AbstractFile] = new mutable.HashSet[AbstractFile] - private val definitions: mutable.Map[AbstractFile, List[Symbols]] = - new mutable.HashMap[AbstractFile, List[Symbols]] { + private val definitions: mutable.Map[AbstractFile, List[SymWithHistory]] = + new mutable.HashMap[AbstractFile, List[SymWithHistory]] { override def default(key: AbstractFile) = Nil } @@ -72,7 +72,7 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana */ private def invalidatedByRemove(files: Set[AbstractFile]): Set[AbstractFile] = { val changes = new mutable.HashMap[Symbol, List[Change]] - for (f <- files; Symbols(sym, _) <- definitions(f)) + for (f <- files; SymWithHistory(sym, _) <- definitions(f)) changes += sym -> List(Removed(Class(sym.fullNameString))) invalidated(files, changes) } @@ -125,13 +125,12 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana definitions(src).find( s => (s.sym.fullNameString == sym.fullNameString) && isCorrespondingSym(s.sym, sym)) match { - case Some(Symbols(oldSym, oldSymEras)) => - val changes = changeSet(oldSym, sym) + case Some(SymWithHistory(oldSym, info)) => + val changes = changeSet(oldSym.info, sym) val changesErasure = atPhase(currentRun.erasurePhase.prev) { - changeSet(oldSymEras, sym) + changeSet(info, sym) } - changesOf(oldSym) = (changes ++ changesErasure).removeDuplicates case _ => // a new top level definition @@ -142,7 +141,7 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana } } // Create a change for the top level classes that were removed - val removed = definitions(src) filterNot ((s:Symbols) => + val removed = definitions(src) filterNot ((s:SymWithHistory) => syms.find(_.fullNameString == (s.sym.fullNameString)) != None) for (s <- removed) { changesOf(s.sym) = List(removeChangeSet(s.sym)) @@ -279,7 +278,11 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana private def updateDefinitions(files: Set[AbstractFile]) { for (src <- files; val localDefs = compiler.dependencyAnalysis.definitions(src)) { definitions(src) = (localDefs map (s => { - Symbols(s.cloneSymbol, atPhase(currentRun.erasurePhase.prev) {s.cloneSymbol}) + SymWithHistory( + s.cloneSymbol, + atPhase(currentRun.erasurePhase.prev) { + s.info.cloneInfo(s) + }) })) } this.references = compiler.dependencyAnalysis.references diff --git a/src/compiler/scala/tools/nsc/interpreter/Completion.scala b/src/compiler/scala/tools/nsc/interpreter/Completion.scala index 2ecafa974a..2b9538b3fc 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Completion.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Completion.scala @@ -31,7 +31,12 @@ import scala.util.NameTransformer.{ decode, encode } // REPL completor - queries supplied interpreter for valid completions // based on current contents of buffer. -class Completion(val interpreter: Interpreter) extends Completor { +class Completion( + val interpreter: Interpreter, + val intLoop: InterpreterLoop) +extends Completor { + def this(interpreter: Interpreter) = this(interpreter, null) + import Completion._ import java.util.{ List => JList } import interpreter.compilerClasspath @@ -59,7 +64,7 @@ class Completion(val interpreter: Interpreter) extends Completor { } // One instance of a command line - class Buffer(s: String) { + class Buffer(s: String, verbose: Boolean) { val buffer = if (s == null) "" else s def isEmptyBuffer = buffer == "" @@ -133,25 +138,29 @@ class Completion(val interpreter: Interpreter) extends Completor { } def membersOfPredef() = membersOfId("scala.Predef") - def javaLangToHide(s: String) = + def javaLangToHide(s: String) = ( (s endsWith "Exception") || (s endsWith "Error") || (s endsWith "Impl") || (s startsWith "CharacterData") || !existsAndPublic("java.lang." + s) + ) def scalaToHide(s: String) = (List("Tuple", "Product", "Function") exists (x => (x + """\d+""").r findPrefixMatchOf s isDefined)) || (List("Exception", "Error") exists (s endsWith _)) - def defaultMembers = (List("scala", "java.lang") flatMap membersOfPath) ::: membersOfPredef + /** Hide all default members not verbose */ + def defaultMembers = + if (verbose) (List("scala", "java.lang") flatMap membersOfPath) ::: membersOfPredef + else Nil def pkgsStartingWith(s: String) = topLevelPackages() filter (_ startsWith s) def idsStartingWith(s: String) = { - // on a totally empty buffer, filter out res* + // only print res* when verbose val unqIds = - if (s == "") interpreter.unqualifiedIds filterNot (_ startsWith INTERPRETER_VAR_PREFIX) - else interpreter.unqualifiedIds + if (verbose) interpreter.unqualifiedIds + else interpreter.unqualifiedIds filterNot (_ startsWith INTERPRETER_VAR_PREFIX) (unqIds ::: defaultMembers) filter (_ startsWith s) } @@ -175,9 +184,21 @@ class Completion(val interpreter: Interpreter) extends Completor { (interpreter getClassObject ("scala." + path)) orElse (interpreter getClassObject ("java.lang." + path)) + def lastHistoryItem = + for (loop <- Option(intLoop) ; h <- loop.history) yield + h.getHistoryList.get(h.size - 1) + + // Is the buffer the same it was last time they hit tab? + private var lastTab: (String, String) = (null, null) + // jline's completion comes through here - we ask a Buffer for the candidates. - override def complete(_buffer: String, cursor: Int, candidates: JList[String]): Int = - new Buffer(_buffer) complete candidates + override def complete(_buffer: String, cursor: Int, candidates: JList[String]): Int = { + // println("_buffer = %s, cursor = %d".format(_buffer, cursor)) + val verbose = (_buffer, lastHistoryItem orNull) == lastTab + lastTab = (_buffer, lastHistoryItem orNull) + + new Buffer(_buffer, verbose) complete candidates + } def completePackageMembers(path: String): List[String] = getClassObject(path + "." + "package") map (getMembers(_, false)) getOrElse Nil diff --git a/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala b/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala index f2eb30cf14..500876bf69 100644 --- a/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala +++ b/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala @@ -38,9 +38,9 @@ object InteractiveReader { /** Create an interactive reader. Uses <code>JLineReader</code> if the * library is available, but otherwise uses a <code>SimpleReader</code>. */ - def createDefault(interpreter: Interpreter): InteractiveReader = + def createDefault(interpreter: Interpreter, intLoop: InterpreterLoop = null): InteractiveReader = catching(exes: _*) - . opt (new JLineReader(interpreter)) + . opt (new JLineReader(interpreter, intLoop)) . getOrElse (new SimpleReader) } diff --git a/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala b/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala index 59d6f0ac0a..b13b54a716 100644 --- a/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala +++ b/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala @@ -11,15 +11,17 @@ import java.io.File import jline.{ History, ConsoleReader, ArgumentCompletor } /** Reads from the console using JLine */ -class JLineReader(interpreter: Interpreter) extends InteractiveReader { - def this() = this(null) +class JLineReader(interpreter: Interpreter, intLoop: InterpreterLoop) extends InteractiveReader { + def this() = this(null, null) + def this(interpreter: Interpreter) = this(interpreter, null) + def history: History = consoleReader.getHistory + val consoleReader = { - val history = try { - new jline.History(new File(System.getProperty("user.home"), ".scala_history")) - } catch { + val history = + try new History(new File(System.getProperty("user.home"), ".scala_history")) // do not store history if error - case _ => new jline.History() - } + catch { case _: Exception => new History() } + val r = new jline.ConsoleReader() r setHistory history r setBellEnabled false @@ -30,7 +32,7 @@ class JLineReader(interpreter: Interpreter) extends InteractiveReader { val delimChars = "(){}[],`;'\" \t".toArray def isDelimiterChar(s: String, pos: Int) = delimChars contains s.charAt(pos) } - val comp = new ArgumentCompletor(new Completion(interpreter), delims) + val comp = new ArgumentCompletor(new Completion(interpreter, intLoop), delims) comp setStrict false r addCompletor comp // XXX make this use a setting diff --git a/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala b/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala index 112b3e1e82..bca2e18e39 100644 --- a/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala +++ b/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala @@ -7,7 +7,7 @@ package scala.tools.nsc package interpreter -import java.io.{BufferedReader, PrintWriter} +import java.io.{ BufferedReader, PrintWriter } /** Reads using standard JDK API */ class SimpleReader( diff --git a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala index c5f09cd8de..4f13d4fd99 100644 --- a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala +++ b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala @@ -115,7 +115,7 @@ trait MatrixAdditions extends ast.TreeDSL object lxtt extends Transformer { override def transform(tree: Tree): Tree = tree match { case blck @ Block(vdefs, ld @ LabelDef(name, params, body)) => - def shouldInline(t: FinalState) = t.isReachedOnce && (t.label eq ld.symbol) + def shouldInline(t: FinalState) = t.isReachedOnce && (t.labelSym eq ld.symbol) if (targets exists shouldInline) squeezedBlock(vdefs, body) else blck diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index fd4b57ef67..7fce0ee73a 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -280,7 +280,9 @@ trait ParallelMatching extends ast.TreeDSL lazy val pvgroup = PatternVarGroup.fromBindings(subst.get()) - final def tree(): Tree = squeezedBlock(pvgroup.valDefs, codegen) + final def tree(): Tree = + if (guard.isEmpty) success + else squeezedBlock(pvgroup.valDefs, codegen) } /** Mixture rule for all literal ints (and chars) i.e. hopefully a switch diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index 7a77095293..e1cf7a5a7e 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -19,7 +19,7 @@ trait Definitions { // Working around bug #2133 private object definitionHelpers { - def cond[T](x: T)(f: T =>? Boolean) = (f isDefinedAt x) && f(x) + def cond[T](x: T)(f: PartialFunction[T, Boolean]) = (f isDefinedAt x) && f(x) } import definitionHelpers._ diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index 9f22bc54f7..5ee7409cc7 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -1238,7 +1238,7 @@ trait Symbols { // appears to succeed but highly opaque errors come later: see bug #1286 if (res == false) { val (f1, f2) = (this.sourceFile, that.sourceFile) - if (f1 != null && f2 != null && f1 != f2) + if (f1 != null && f2 != null && f1.path != f2.path) throw FatalError("Companions '" + this + "' and '" + that + "' must be defined in same file.") } @@ -1254,21 +1254,28 @@ trait Symbols { else NoSymbol } + /** A helper method that factors the common code used the discover a companion module of a class. If a companion + * module exists, its symbol is returned, otherwise, `NoSymbol` is returned. The method assumes that `this` + * symbol has already been checked to be a class (using `isClass`). */ + private final def linkedModuleOfClass0: Symbol = + flatOwnerInfo.decl(name.toTermName).suchThat( + sym => (sym hasFlag MODULE) && (sym isCoDefinedWith this)) + /** The module or case class factory with the same name in the same * package as this class. A better name would be companionModuleOfClass. */ final def linkedModuleOfClass: Symbol = - if (this.isClass && !this.isAnonymousClass && !this.isRefinementClass) { - flatOwnerInfo.decl(name.toTermName).suchThat( - sym => (sym hasFlag MODULE) && (sym isCoDefinedWith this)) - } else NoSymbol + if (this.isClass && !this.isAnonymousClass && !this.isRefinementClass) + linkedModuleOfClass0 + else NoSymbol /** For a module its linked class, for a class its linked module or case * factory otherwise. */ final def linkedSym: Symbol = if (isTerm) linkedClassOfModule - else if (isClass) flatOwnerInfo.decl(name.toTermName).suchThat(_ isCoDefinedWith this) + else if (isClass) + linkedModuleOfClass0 else NoSymbol /** For a module class its linked class, for a plain class diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index be537010f6..c9aab59ff5 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -98,7 +98,7 @@ trait Types { /** Undo all changes to constraints to type variables upto `limit' */ private def undoTo(limit: UndoLog) { - while (log ne limit) { + while ((log ne limit) && log.nonEmpty) { val (tv, constr) = log.head tv.constr = constr log = log.tail @@ -503,40 +503,20 @@ trait Types { /** The info of `sym', seen as a member of this type. */ - def memberInfo(sym: Symbol): Type = + def memberInfo(sym: Symbol): Type = { + // incCounter(ctr1) sym.info.asSeenFrom(this, sym.owner) + } /** The type of `sym', seen as a member of this type. */ def memberType(sym: Symbol): Type = { - trackTypeIDE(sym) + // incCounter(ctr2) //@M don't prematurely instantiate higher-kinded types, they will be instantiated by transform, typedTypeApply, etc. when really necessary sym.tpeHK match { case ov @ OverloadedType(pre, alts) => OverloadedType(this, alts) -/* - val pre1 = pre match { - case ClassInfoType(_, _, clazz) => clazz.tpe - case _ => pre - } - if (this =:= pre1) ov - else if (this =:= pre1.narrow) OverloadedType(this, alts) - else { - Console.println("bad memberType of overloaded symbol: "+this+"/"+pre1+"/"+pre1.narrow) - assert(false) - ov - } -*/ case tp => - val res = tp.asSeenFrom(this, sym.owner) -/* - if (sym.name.toString == "Elem") { - println("pre = "+this) - println("pre.normalize = "+this.widen.normalize) - println("sym = "+sym+" in "+sym.ownerChain) - println("result = "+res) - } -*/ - res + tp.asSeenFrom(this, sym.owner) } } @@ -595,20 +575,21 @@ trait Types { /** Is this type a subtype of that type? */ def <:<(that: Type): Boolean = { if (util.Statistics.enabled) stat_<:<(that) - else + else { (this eq that) || (if (explainSwitch) explain("<:", isSubType, this, that) else isSubType(this, that, AnyDepth)) + } } def stat_<:<(that: Type): Boolean = { incCounter(subtypeCount) - val start = startTimer(subtypeNanos) +// val start = startTimer(subtypeNanos) val result = (this eq that) || (if (explainSwitch) explain("<:", isSubType, this, that) else isSubType(this, that, AnyDepth)) - stopTimer(subtypeNanos, start) +// stopTimer(subtypeNanos, start) result } @@ -616,12 +597,12 @@ trait Types { */ def weak_<:<(that: Type): Boolean = { incCounter(subtypeCount) - val start = startTimer(subtypeNanos) +// val start = startTimer(subtypeNanos) val result = ((this eq that) || (if (explainSwitch) explain("weak_<:", isWeakSubType, this, that) else isWeakSubType(this, that))) - stopTimer(subtypeNanos, start) +// stopTimer(subtypeNanos, start) result } @@ -796,8 +777,8 @@ trait Types { var member: Symbol = NoSymbol var excluded = excludedFlags | DEFERRED var continue = true - lazy val self: Type = this.narrow - lazy val membertpe = self.memberType(member) + var self: Type = null + var membertpe: Type = null while (continue) { continue = false val bcs0 = baseClasses @@ -821,22 +802,25 @@ trait Types { } else if (member == NoSymbol) { member = sym } else if (members eq null) { -// val start = startTimer(timer1) if (member.name != sym.name || !(member == sym || member.owner != sym.owner && - !sym.hasFlag(PRIVATE) && - (membertpe matches self.memberType(sym)))) { + !sym.hasFlag(PRIVATE) && { + if (self eq null) self = this.narrow + if (membertpe eq null) membertpe = self.memberType(member) + (membertpe matches self.memberType(sym)) + })) { members = new Scope(List(member, sym)) } -// stopTimer(timer1, start) } else { var prevEntry = members.lookupEntry(sym.name) while ((prevEntry ne null) && !(prevEntry.sym == sym || prevEntry.sym.owner != sym.owner && - !sym.hasFlag(PRIVATE) && - (self.memberType(prevEntry.sym) matches self.memberType(sym)))) { + !sym.hasFlag(PRIVATE) && { + if (self eq null) self = this.narrow + self.memberType(prevEntry.sym) matches self.memberType(sym) + })) { prevEntry = members lookupNextEntry prevEntry } if (prevEntry eq null) { @@ -1237,7 +1221,7 @@ trait Types { def memo[A](op1: => A)(op2: Type => A) = intersectionWitness get parents match { case Some(w) => if (w eq this) op1 else op2(w) - case None => + case none => intersectionWitness(parents) = this op1 } @@ -1288,7 +1272,7 @@ trait Types { * If they are several higher-kinded parents with different bounds we need * to take the intersection of their bounds */ - override def normalize = + override def normalize = { if (isHigherKinded) PolyType( typeParams, @@ -1300,6 +1284,7 @@ trait Types { }, decls)) else super.normalize + } /** A refined type P1 with ... with Pn { decls } is volatile if * one of the parent types Pi is an abstract type, and @@ -1380,7 +1365,7 @@ trait Types { */ private def getRefs(which: Int, from: Symbol): Set[Symbol] = refs(which) get from match { case Some(set) => set - case None => Set() + case none => Set() } /** Augment existing refs map with reference <pre>from -> to</pre> @@ -1523,7 +1508,7 @@ trait Types { sym.isAbstractType && bounds.hi.isVolatile override val isTrivial: Boolean = - pre.isTrivial && !sym.isTypeParameter && args.forall(_.isTrivial) + !sym.isTypeParameter && pre.isTrivial && args.forall(_.isTrivial) override def isNotNull = sym.isModuleClass || sym == NothingClass || isValueClass(sym) || super.isNotNull @@ -1668,13 +1653,15 @@ A type's typeSymbol should never be inspected directly. // TODO: no test case in the suite because don't know how to tell partest to compile in different runs, // and in a specific order private var normalizeTyparCount = -1 - override def normalize: Type = + + override def normalize: Type = { if (phase.erasedTypes) normalize0 else if (normalized == null || typeParamsDirect.length != normalizeTyparCount) { normalizeTyparCount = typeParamsDirect.length normalized = normalize0 normalized } else normalized + } override def decls: Scope = { sym.info match { @@ -2546,7 +2533,7 @@ A type's typeSymbol should never be inspected directly. case TypeRef(_, sym, _) => occurCount get sym match { case Some(count) => occurCount += (sym -> (count + 1)) - case None => + case none => } case _ => } @@ -2745,13 +2732,18 @@ A type's typeSymbol should never be inspected directly. /** Map this function over given type */ def mapOver(tp: Type): Type = tp match { - case ErrorType => tp - case WildcardType => tp - case NoType => tp - case NoPrefix => tp + case TypeRef(pre, sym, args) => + val pre1 = this(pre) + //val args1 = args mapConserve this(_) + val args1 = if (args.isEmpty) args + else { + val tparams = sym.typeParams + if (tparams.isEmpty) args + else mapOverArgs(args, tparams) + } + if ((pre1 eq pre) && (args1 eq args)) tp + else typeRef(pre1, sym, args1) case ThisType(_) => tp - case ConstantType(_) => tp - case DeBruijnIndex(_, _) => tp case SingleType(pre, sym) => if (sym.isPackageClass) tp // short path else { @@ -2759,22 +2751,28 @@ A type's typeSymbol should never be inspected directly. if (pre1 eq pre) tp else singleType(pre1, sym) } + case MethodType(params, result) => + variance = -variance + val params1 = mapOver(params) + variance = -variance + val result1 = this(result) + if ((params1 eq params) && (result1 eq result)) tp + // for new dependent types: result1.substSym(params, params1)? + else copyMethodType(tp, params1, result1.substSym(params, params1)) + case PolyType(tparams, result) => + variance = -variance + val tparams1 = mapOver(tparams) + variance = -variance + var result1 = this(result) + if ((tparams1 eq tparams) && (result1 eq result)) tp + else PolyType(tparams1, result1.substSym(tparams, tparams1)) + case ConstantType(_) => tp + case DeBruijnIndex(_, _) => tp case SuperType(thistp, supertp) => val thistp1 = this(thistp) val supertp1 = this(supertp) if ((thistp1 eq thistp) && (supertp1 eq supertp)) tp else mkSuperType(thistp1, supertp1) - case TypeRef(pre, sym, args) => - val pre1 = this(pre) - //val args1 = args mapConserve this(_) - val args1 = if (args.isEmpty) args - else { - val tparams = sym.typeParams - if (tparams.isEmpty) args - else mapOverArgs(args, tparams) - } - if ((pre1 eq pre) && (args1 eq args)) tp - else typeRef(pre1, sym, args1) case TypeBounds(lo, hi) => variance = -variance val lo1 = this(lo) @@ -2792,28 +2790,6 @@ A type's typeSymbol should never be inspected directly. //if ((parents1 eq parents) && (decls1 eq decls)) tp //else refinementOfClass(tp.typeSymbol, parents1, decls1) copyRefinedType(rtp, parents1, decls1) -/* - case ClassInfoType(parents, decls, clazz) => - val parents1 = parents mapConserve (this); - val decls1 = mapOver(decls); - if ((parents1 eq parents) && (decls1 eq decls)) tp - else cloneDecls(ClassInfoType(parents1, new Scope(), clazz), tp, decls1) -*/ - case MethodType(params, result) => - variance = -variance - val params1 = mapOver(params) - variance = -variance - val result1 = this(result) - if ((params1 eq params) && (result1 eq result)) tp - // for new dependent types: result1.substSym(params, params1)? - else copyMethodType(tp, params1, result1.substSym(params, params1)) - case PolyType(tparams, result) => - variance = -variance - val tparams1 = mapOver(tparams) - variance = -variance - var result1 = this(result) - if ((tparams1 eq tparams) && (result1 eq result)) tp - else PolyType(tparams1, result1.substSym(tparams, tparams1)) case ExistentialType(tparams, result) => val tparams1 = mapOver(tparams) var result1 = this(result) @@ -2841,6 +2817,12 @@ A type's typeSymbol should never be inspected directly. if ((annots1 eq annots) && (atp1 eq atp)) tp else if (annots1.isEmpty) atp1 else AnnotatedType(annots1, atp1, selfsym) +/* + case ErrorType => tp + case WildcardType => tp + case NoType => tp + case NoPrefix => tp +*/ case _ => tp // throw new Error("mapOver inapplicable for " + tp); @@ -3055,13 +3037,13 @@ A type's typeSymbol should never be inspected directly. def stabilize(pre: Type, clazz: Symbol): Type = { capturedPre get clazz match { - case None => + case Some(qvar) => + qvar + case _ => val qvar = clazz freshExistential ".type" setInfo singletonBounds(pre) capturedPre += (clazz -> qvar) capturedParams = qvar :: capturedParams qvar - case Some(qvar) => - qvar } }.tpe @@ -3076,6 +3058,7 @@ A type's typeSymbol should never be inspected directly. if (b == NoType && clazz.isRefinementClass) pre else b } + def apply(tp: Type): Type = if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) tp else tp match { @@ -3255,7 +3238,7 @@ A type's typeSymbol should never be inspected directly. } else { giveup() } - case None => super.transform(tree) + case none => super.transform(tree) } case tree => super.transform(tree) } @@ -3761,21 +3744,22 @@ A type's typeSymbol should never be inspected directly. /** Do `tp1' and `tp2' denote equivalent types? */ - def isSameType(tp1: Type, tp2: Type): Boolean = try { + def isSameType(tp1: Type, tp2: Type): Boolean = { val start = startTimer(timer1); try { incCounter(sametypeCount) subsametypeRecursions += 1 undoLog undoUnless { - isSameType0(tp1, tp2) + isSameType1(tp1, tp2) } } finally { subsametypeRecursions -= 1 - if (subsametypeRecursions == 0) undoLog clear - } + if (subsametypeRecursions == 0) undoLog.clear + stopTimer(timer1, start) + }} def isDifferentType(tp1: Type, tp2: Type): Boolean = try { subsametypeRecursions += 1 undoLog undo { // undo type constraints that arise from operations in this block - !isSameType0(tp1, tp2) + !isSameType1(tp1, tp2) } } finally { subsametypeRecursions -= 1 @@ -3806,7 +3790,8 @@ A type's typeSymbol should never be inspected directly. } */ - private def isSameType0(tp1: Type, tp2: Type): Boolean = + private def isSameType0(tp1: Type, tp2: Type): Boolean = { + if (tp1 eq tp2) return true ((tp1, tp2) match { case (ErrorType, _) => true case (WildcardType, _) => true @@ -3822,7 +3807,7 @@ A type's typeSymbol should never be inspected directly. if (sym1 == sym2) => true case (SingleType(pre1, sym1), SingleType(pre2, sym2)) - if equalSymsAndPrefixes(sym1, pre1, sym2, pre2) => + if (equalSymsAndPrefixes(sym1, pre1, sym2, pre2)) => true /* case (SingleType(pre1, sym1), ThisType(sym2)) @@ -3908,6 +3893,162 @@ A type's typeSymbol should never be inspected directly. val tp2n = normalizePlus(tp2) ((tp1n ne tp1) || (tp2n ne tp2)) && isSameType(tp1n, tp2n) } + } + + private def isSameType1(tp1: Type, tp2: Type): Boolean = { + if ((tp1 eq tp2) || + (tp1 eq ErrorType) || (tp1 eq WildcardType) || + (tp2 eq ErrorType) || (tp2 eq WildcardType)) + true + else if ((tp1 eq NoType) || (tp2 eq NoType)) + false + else if (tp1 eq NoPrefix) + tp2.typeSymbol.isPackageClass + else if (tp2 eq NoPrefix) + tp1.typeSymbol.isPackageClass + else { + isSameType2(tp1, tp2) || { + val tp1n = normalizePlus(tp1) + val tp2n = normalizePlus(tp2) + ((tp1n ne tp1) || (tp2n ne tp2)) && isSameType(tp1n, tp2n) + } + } + } + + def isSameType2(tp1: Type, tp2: Type): Boolean = { + tp1 match { + case tr1: TypeRef => + tp2 match { + case tr2: TypeRef => + return equalSymsAndPrefixes(tr1.sym, tr1.pre, tr2.sym, tr2.pre) && + ((tp1.isHigherKinded && tp2.isHigherKinded && tp1.normalize =:= tp2.normalize) || + isSameTypes(tr1.args, tr2.args)) + case _ => + } + case ThisType(sym1) => + tp2 match { + case ThisType(sym2) => + if (sym1 == sym2) return true + case _ => + } + case SingleType(pre1, sym1) => + tp2 match { + case SingleType(pre2, sym2) => + if (equalSymsAndPrefixes(sym1, pre1, sym2, pre2)) return true + case _ => + } + case ConstantType(value1) => + tp2 match { + case ConstantType(value2) => + return (value1 == value2) + case _ => + } + case RefinedType(parents1, ref1) => + tp2 match { + case RefinedType(parents2, ref2) => + def isSubScope(s1: Scope, s2: Scope): Boolean = s2.toList.forall { + sym2 => + var e1 = s1.lookupEntry(sym2.name) + (e1 ne null) && { + val substSym = sym2.info.substThis(sym2.owner, e1.sym.owner.thisType) + var isEqual = false + while (!isEqual && (e1 ne null)) { + isEqual = e1.sym.info =:= substSym + e1 = s1.lookupNextEntry(e1) + } + isEqual + } + } + //Console.println("is same? " + tp1 + " " + tp2 + " " + tp1.typeSymbol.owner + " " + tp2.typeSymbol.owner)//DEBUG + return isSameTypes(parents1, parents2) && + isSubScope(ref1, ref2) && isSubScope(ref2, ref1) + case _ => + } + case MethodType(params1, res1) => + tp2 match { + case MethodType(params2, res2) => + // new dependent types: probably fix this, use substSym as done for PolyType + return isSameTypes(tp1.paramTypes, tp2.paramTypes) && + res1 =:= res2 && + tp1.isInstanceOf[ImplicitMethodType] == tp2.isInstanceOf[ImplicitMethodType] + case _ => + } + case PolyType(tparams1, res1) => + tp2 match { + case PolyType(tparams2, res2) => +// assert((tparams1 map (_.typeParams.length)) == (tparams2 map (_.typeParams.length))) + return tparams1.length == tparams2.length && + (tparams1, tparams2).zipped.forall((p1, p2) => + p1.info =:= p2.info.substSym(tparams2, tparams1)) && //@M looks like it might suffer from same problem as #2210 + res1 =:= res2.substSym(tparams2, tparams1) + case _ => + } + case ExistentialType(tparams1, res1) => + tp2 match { + case ExistentialType(tparams2, res2) => + return (tparams1.length == tparams2.length && + (tparams1, tparams2).zipped.forall + ((p1, p2) => p1.info =:= p2.info.substSym(tparams2, tparams1)) && //@M looks like it might suffer from same problem as #2210 + res1 =:= res2.substSym(tparams2, tparams1)) + case _ => + } + case TypeBounds(lo1, hi1) => + tp2 match { + case TypeBounds(lo2, hi2) => + return lo1 =:= lo2 && hi1 =:= hi2 + case _ => + } + case BoundedWildcardType(bounds) => + return bounds containsType tp2 + case _ => + } + tp2 match { + case BoundedWildcardType(bounds) => + return bounds containsType tp1 + case _ => + } + tp1 match { + case tv @ TypeVar(_,_) => + return tv.registerTypeEquality(tp2, true) + case _ => + } + tp2 match { + case tv @ TypeVar(_,_) => + return tv.registerTypeEquality(tp1, false) + case _ => + } + tp1 match { + case AnnotatedType(_,_,_) => + return annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) && tp1.withoutAnnotations =:= tp2.withoutAnnotations + case _ => + } + tp2 match { + case AnnotatedType(_,_,_) => + return annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) && tp1.withoutAnnotations =:= tp2.withoutAnnotations + case _ => + } + tp1 match { + case _: SingletonType => + tp2 match { + case _: SingletonType => + var origin1 = tp1 + while (origin1.underlying.isInstanceOf[SingletonType]) { + assert(origin1 ne origin1.underlying, origin1) + origin1 = origin1.underlying + } + var origin2 = tp2 + while (origin2.underlying.isInstanceOf[SingletonType]) { + assert(origin2 ne origin2.underlying, origin2) + origin2 = origin2.underlying + } + ((origin1 ne tp1) || (origin2 ne tp2)) && (origin1 =:= origin2) + case _ => + false + } + case _ => + false + } + } /** Are `tps1' and `tps2' lists of pairwise equivalent * types? diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index 09ed32253a..cf217dcd23 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -280,7 +280,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { val testForBoolean: Tree = (qual IS_OBJ BoxedBooleanClass.tpe) val testForNumberOrBoolean = testForNumber OR testForBoolean - val getPrimitiveReplacementForStructuralCall: Name =>? (Symbol, Tree) = { + val getPrimitiveReplacementForStructuralCall: PartialFunction[Name, (Symbol, Tree)] = { val testsForNumber = Map() ++ List( nme.UNARY_+ -> "positive", nme.UNARY_- -> "negate", diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index de9dadbd1f..e92ba64469 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -120,16 +120,23 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. // Compute the erasure of the intersection type with given `parents` according to new spec. private def intersectionErasure(parents: List[Type]): Type = if (parents.isEmpty) erasedTypeRef(ObjectClass) - else { - // implement new spec for erasure of refined types. + else apply { val psyms = parents map (_.typeSymbol) - def isUnshadowed(psym: Symbol) = - !(psyms exists (qsym => (psym ne qsym) && (qsym isNonBottomSubClass psym))) - val cs = parents.iterator.filter { p => // isUnshadowed is a bit expensive, so try classes first - val psym = p.typeSymbol - psym.isClass && !psym.isTrait && isUnshadowed(psym) + if (psyms contains ArrayClass) { + // treat arrays specially + arrayType( + intersectionErasure( + parents filter (_.typeSymbol == ArrayClass) map (_.typeArgs.head))) + } else { + // implement new spec for erasure of refined types. + def isUnshadowed(psym: Symbol) = + !(psyms exists (qsym => (psym ne qsym) && (qsym isNonBottomSubClass psym))) + val cs = parents.iterator.filter { p => // isUnshadowed is a bit expensive, so try classes first + val psym = p.typeSymbol + psym.isClass && !psym.isTrait && isUnshadowed(psym) + } + (if (cs.hasNext) cs else parents.iterator.filter(p => isUnshadowed(p.typeSymbol))).next() } - apply((if (cs.hasNext) cs else parents.iterator.filter(p => isUnshadowed(p.typeSymbol))).next()) } def apply(tp: Type): Type = { diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 0727835e00..6937658534 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -739,8 +739,9 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { override def mapOver(tp: Type): Type = tp match { case ClassInfoType(parents, decls, clazz) => val parents1 = parents mapConserve (this); - val decls1 = mapOver(decls.toList); - if ((parents1 eq parents) && (decls1 eq decls)) tp + val declsList = decls.toList + val decls1 = mapOver(declsList); + if ((parents1 eq parents) && (decls1 eq declsList)) tp else ClassInfoType(parents1, new Scope(decls1), clazz) case AnnotatedType(annots, atp, selfsym) => val annots1 = mapOverAnnotations(annots) @@ -1254,7 +1255,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { for (tp <- owner.info.memberType(target).typeParams) yield if (!env.isDefinedAt(tp)) - typeRef(NoPrefix, from.info.typeParams.find(_ == tp.name).get, Nil) + typeRef(NoPrefix, from.info.typeParams.find(_.name == tp.name).get, Nil) else if ((env(tp) <:< tp.info.bounds.hi) && (tp.info.bounds.lo <:< env(tp))) env(tp) else tp.info.bounds.hi diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index fd5dd0f9a3..dc475b4173 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -296,11 +296,11 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { * } * new $anon() * - * transform a function node (x => body) of type T =>? R where + * transform a function node (x => body) of type PartialFunction[T, R] where * body = expr match { case P_i if G_i => E_i }_i=1..n * to: * - * class $anon() extends Object() with T =>? R with ScalaObject { + * class $anon() extends Object() with PartialFunction[T, R] with ScalaObject { * def apply(x: T): R = (expr: @unchecked) match { * { case P_i if G_i => E_i }_i=1..n * def isDefinedAt(x: T): boolean = (x: @unchecked) match { diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 2acc09b70e..dd592bb96d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -180,7 +180,7 @@ trait Contexts { self: Analyzer => scope: Scope, imports: List[ImportInfo]): Context = { val c = new Context c.unit = unit - c.tree = sanitize(tree) + c.tree = /*sanitize*/(tree) // used to be for IDE c.owner = owner c.scope = scope @@ -464,20 +464,35 @@ trait Contexts { self: Analyzer => implicitsCache = null if (outer != null && outer != this) outer.resetCache } - private def collectImplicits(syms: List[Symbol], pre: Type): List[ImplicitInfo] = - for (sym <- syms if sym.hasFlag(IMPLICIT) && isAccessible(sym, pre, false)) + + /** A symbol `sym` qualifies as an implicit if it has the IMPLICIT flag set, + * it is accessible, and if it is imported there is not already a local symbol + * with the same names. Local symbols override imported ones. This fixes #2866. + */ + private def isQualifyingImplicit(sym: Symbol, pre: Type, imported: Boolean) = + sym.hasFlag(IMPLICIT) && + isAccessible(sym, pre, false) && + !(imported && { + val e = scope.lookupEntry(sym.name) + (e ne null) && (e.owner == scope) + }) + + private def collectImplicits(syms: List[Symbol], pre: Type, imported: Boolean = false): List[ImplicitInfo] = + for (sym <- syms if isQualifyingImplicit(sym, pre, imported)) yield new ImplicitInfo(sym.name, pre, sym) private def collectImplicitImports(imp: ImportInfo): List[ImplicitInfo] = { val pre = imp.qual.tpe def collect(sels: List[ImportSelector]): List[ImplicitInfo] = sels match { - case List() => List() - case List(ImportSelector(nme.WILDCARD, _, _, _)) => collectImplicits(pre.implicitMembers, pre) + case List() => + List() + case List(ImportSelector(nme.WILDCARD, _, _, _)) => + collectImplicits(pre.implicitMembers, pre, imported = true) case ImportSelector(from, _, to, _) :: sels1 => var impls = collect(sels1) filter (info => info.name != from) if (to != nme.WILDCARD) { for (sym <- imp.importedSymbol(to).alternatives) - if (sym.hasFlag(IMPLICIT) && isAccessible(sym, pre, false)) + if (isQualifyingImplicit(sym, pre, imported = true)) impls = new ImplicitInfo(to, pre, sym) :: impls } impls @@ -488,7 +503,6 @@ trait Contexts { self: Analyzer => def implicitss: List[List[ImplicitInfo]] = { val nextOuter = if (owner.isConstructor) outer.outer.outer else outer - // can we can do something smarter to bring back the implicit cache? if (implicitsRunId != currentRunId) { implicitsRunId = currentRunId implicitsCache = List() @@ -545,7 +559,7 @@ trait Contexts { self: Analyzer => /** The prefix expression */ def qual: Tree = tree.symbol.info match { case ImportType(expr) => expr - case ErrorType => tree + case ErrorType => tree setType NoType // fix for #2870 case _ => throw new FatalError("symbol " + tree.symbol + " has bad type: " + tree.symbol.info);//debug } @@ -561,16 +575,16 @@ trait Contexts { self: Analyzer => var renamed = false var selectors = tree.selectors while (selectors != Nil && result == NoSymbol) { - if (selectors.head.name != nme.WILDCARD) - notifyImport(name, qual.tpe, selectors.head.name, selectors.head.rename) +// if (selectors.head.name != nme.WILDCARD) // used to be for IDE +// notifyImport(name, qual.tpe, selectors.head.name, selectors.head.rename) if (selectors.head.rename == name.toTermName) - result = qual.tpe.member( + result = qual.tpe.nonLocalMember( // new to address #2733: consider only non-local members for imports if (name.isTypeName) selectors.head.name.toTypeName else selectors.head.name) else if (selectors.head.name == name.toTermName) renamed = true else if (selectors.head.name == nme.WILDCARD && !renamed) - result = qual.tpe.member(name) + result = qual.tpe.nonLocalMember(name) selectors = selectors.tail } result diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 9657cea101..0539b4ee17 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -459,7 +459,9 @@ self: Analyzer => if (traceImplicits) println("tvars = "+tvars+"/"+(tvars map (_.constr))) val targs = solvedTypes(tvars, undetParams, undetParams map varianceInType(pt), false, lubDepth(List(itree2.tpe, pt))) - checkBounds(itree2.pos, NoPrefix, NoSymbol, undetParams, targs, "inferred ") // #2421 + + // #2421: check that we correctly instantiated type parameters outside of the implicit tree: + checkBounds(itree2.pos, NoPrefix, NoSymbol, undetParams, targs, "inferred ") // filter out failures from type inference, don't want to remove them from undetParams! // we must be conservative in leaving type params in undetparams @@ -472,6 +474,18 @@ self: Analyzer => val subst = new TreeTypeSubstituter(okParams, okArgs) subst traverse itree2 + // #2421b: since type inference (which may have been performed during implicit search) + // does not check whether inferred arguments meet the bounds of the corresponding parameter (see note in solvedTypes), + // must check again here: + itree2 match { // roughly equivalent to typed1(itree2, EXPRmode, wildPt), + // since typed1 only forces checking of the outer tree and calls typed on the subtrees + // (they have already been type checked, by the typed1(itree...) above, so the subtrees are skipped by typed) + // inlining the essential bit here for clarity + //TODO: verify that these subtrees don't need re-checking + case TypeApply(fun, args) => typedTypeApply(itree2, EXPRmode, fun, args) + case _ => + } + val result = new SearchResult(itree2, subst) incCounter(foundImplicits) if (traceImplicits) println("RESULT = "+result) diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 5c6788f0f6..621b6dce11 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -159,6 +159,9 @@ trait Infer { if (!solve(tvars, tparams, variances, upper, depth)) { // no panic, it's good enough to just guess a solution, we'll find out // later whether it works. +// @M danger, Will Robinson! this means that you should never trust inferred type arguments! +// need to call checkBounds on the args/typars or type1 on the tree for the expression that results from type inference +// see e.g., #2421: implicit search had been ignoring this caveat // throw new DeferredNoInstance(() => // "no solution exists for constraints"+(tvars map boundsString)) } @@ -990,12 +993,12 @@ trait Infer { val specificCount = (if (isAsSpecific(ftpe1, ftpe2)) 1 else 0) - (if (isAsSpecific(ftpe2, ftpe1) && // todo: move to isAsSepecific test - (!ftpe2.isInstanceOf[OverloadedType] || ftpe1.isInstanceOf[OverloadedType]) && +// (!ftpe2.isInstanceOf[OverloadedType] || ftpe1.isInstanceOf[OverloadedType]) && (!phase.erasedTypes || covariantReturnOverride(ftpe1, ftpe2))) 1 else 0) val subClassCount = (if (isInProperSubClassOrObject(sym1, sym2)) 1 else 0) - (if (isInProperSubClassOrObject(sym2, sym1)) 1 else 0) - //println("is more specific? "+sym1+sym1.locationString+"/"+sym2+sym2.locationString+":"+ - // specificCount+"/"+subClassCount) +// println("is more specific? "+sym1+":"+ftpe1+sym1.locationString+"/"+sym2+":"+ftpe2+sym2.locationString+":"+ +// specificCount+"/"+subClassCount) specificCount + subClassCount > 0 } } @@ -1714,6 +1717,7 @@ trait Infer { }) def improves(sym1: Symbol, sym2: Symbol) = +// util.trace("improve "+sym1+sym1.locationString+" on "+sym2+sym2.locationString)( sym2 == NoSymbol || sym2.isError || isStrictlyMoreSpecific(followApply(pre.memberType(sym1)), followApply(pre.memberType(sym2)), sym1, sym2) diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 1955348f91..ae8fd3a956 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1188,8 +1188,10 @@ trait Namers { self: Analyzer => def checkSelectors(selectors: List[ImportSelector]): Unit = selectors match { case ImportSelector(from, _, to, _) :: rest => if (from != nme.WILDCARD && base != ErrorType) { - if (base.member(from) == NoSymbol && base.member(from.toTypeName) == NoSymbol) - context.error(tree.pos, from.decode + " is not a member of " + expr); + if (base.nonLocalMember(from) == NoSymbol && + base.nonLocalMember(from.toTypeName) == NoSymbol) + context.error(tree.pos, from.decode + " is not a member of " + expr) + if (checkNotRedundant(tree.pos, from, to)) checkNotRedundant(tree.pos, from.toTypeName, to.toTypeName) } diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index e59b469057..257ab243b4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -149,7 +149,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT for (member <- sym.info.members) { println(member+":"+sym.thisType.memberInfo(member)+"\n"+ toJavaDoc(expandedDocComment(member, sym))) - for ((useCase, comment) <- useCases(member, sym)) { + for ((useCase, comment, pos) <- useCases(member, sym)) { println("usecase "+useCase+":"+useCase.info) println(toJavaDoc(comment)) } diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 676279a8d2..9ae56f05a3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -175,10 +175,13 @@ trait SyntheticMethods extends ast.TreeDSL { def makeTrees(acc: Symbol, cpt: Type): (Tree, Bind) = { val varName = context.unit.fresh.newName(clazz.pos.focus, acc.name + "$") val (eqMethod, binding) = - if (isRepeatedParamType(cpt)) (nme.sameElements, Star(WILD())) - else (nme.EQ , WILD() ) - - ((varName DOT eqMethod)(Ident(acc)), varName BIND binding) + if (isRepeatedParamType(cpt)) + (TypeApply(varName DOT nme.sameElements, List(TypeTree(cpt.baseType(SeqClass).typeArgs.head))), + Star(WILD())) + else + ((varName DOT nme.EQ): Tree, + WILD()) + (eqMethod APPLY Ident(acc), varName BIND binding) } // Creates list of parameters and a guard for each diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index f29f6fa7a3..515c7ad354 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2900,6 +2900,56 @@ trait Typers { self: Analyzer => TypeTree(ExistentialType(typeParams, tpe)) setOriginal tree } + // lifted out of typed1 because it's needed in typedImplicit0 + protected def typedTypeApply(tree: Tree, mode: Int, fun: Tree, args: List[Tree]): Tree = fun.tpe match { + case OverloadedType(pre, alts) => + inferPolyAlternatives(fun, args map (_.tpe)) + val tparams = fun.symbol.typeParams //@M TODO: fun.symbol.info.typeParams ? (as in typedAppliedTypeTree) + val args1 = if(args.length == tparams.length) { + //@M: in case TypeApply we can't check the kind-arities of the type arguments, + // as we don't know which alternative to choose... here we do + map2Conserve(args, tparams) { + //@M! the polytype denotes the expected kind + (arg, tparam) => typedHigherKindedType(arg, mode, polyType(tparam.typeParams, AnyClass.tpe)) + } + } else // @M: there's probably something wrong when args.length != tparams.length... (triggered by bug #320) + // Martin, I'm using fake trees, because, if you use args or arg.map(typedType), + // inferPolyAlternatives loops... -- I have no idea why :-( + // ...actually this was looping anyway, see bug #278. + return errorTree(fun, "wrong number of type parameters for "+treeSymTypeMsg(fun)) + + typedTypeApply(tree, mode, fun, args1) + case SingleType(_, _) => + typedTypeApply(tree, mode, fun setType fun.tpe.widen, args) + case PolyType(tparams, restpe) if (tparams.length != 0) => + if (tparams.length == args.length) { + val targs = args map (_.tpe) + checkBounds(tree.pos, NoPrefix, NoSymbol, tparams, targs, "") + if (fun.symbol == Predef_classOf) { + checkClassType(args.head, true, false) + atPos(tree.pos) { gen.mkClassOf(targs.head) } + } else { + if (phase.id <= currentRun.typerPhase.id && + fun.symbol == Any_isInstanceOf && !targs.isEmpty) + checkCheckable(tree.pos, targs.head, "") + val resultpe = restpe.instantiateTypeParams(tparams, targs) + //@M substitution in instantiateParams needs to be careful! + //@M example: class Foo[a] { def foo[m[x]]: m[a] = error("") } (new Foo[Int]).foo[List] : List[Int] + //@M --> first, m[a] gets changed to m[Int], then m gets substituted for List, + // this must preserve m's type argument, so that we end up with List[Int], and not List[a] + //@M related bug: #1438 + //println("instantiating type params "+restpe+" "+tparams+" "+targs+" = "+resultpe) + treeCopy.TypeApply(tree, fun, args) setType resultpe + } + } else { + errorTree(tree, "wrong number of type parameters for "+treeSymTypeMsg(fun)) + } + case ErrorType => + setError(tree) + case _ => + errorTree(tree, treeSymTypeMsg(fun)+" does not take type parameters.") + } + /** * @param tree ... * @param mode ... @@ -3184,55 +3234,6 @@ trait Typers { self: Analyzer => errorTree(expr1, "_ must follow method; cannot follow " + expr1.tpe) } - def typedTypeApply(fun: Tree, args: List[Tree]): Tree = fun.tpe match { - case OverloadedType(pre, alts) => - inferPolyAlternatives(fun, args map (_.tpe)) - val tparams = fun.symbol.typeParams //@M TODO: fun.symbol.info.typeParams ? (as in typedAppliedTypeTree) - val args1 = if(args.length == tparams.length) { - //@M: in case TypeApply we can't check the kind-arities of the type arguments, - // as we don't know which alternative to choose... here we do - map2Conserve(args, tparams) { - //@M! the polytype denotes the expected kind - (arg, tparam) => typedHigherKindedType(arg, mode, polyType(tparam.typeParams, AnyClass.tpe)) - } - } else // @M: there's probably something wrong when args.length != tparams.length... (triggered by bug #320) - // Martin, I'm using fake trees, because, if you use args or arg.map(typedType), - // inferPolyAlternatives loops... -- I have no idea why :-( - // ...actually this was looping anyway, see bug #278. - return errorTree(fun, "wrong number of type parameters for "+treeSymTypeMsg(fun)) - - typedTypeApply(fun, args1) - case SingleType(_, _) => - typedTypeApply(fun setType fun.tpe.widen, args) - case PolyType(tparams, restpe) if (tparams.length != 0) => - if (tparams.length == args.length) { - val targs = args map (_.tpe) - checkBounds(tree.pos, NoPrefix, NoSymbol, tparams, targs, "") - if (fun.symbol == Predef_classOf) { - checkClassType(args.head, true, false) - atPos(tree.pos) { gen.mkClassOf(targs.head) } - } else { - if (phase.id <= currentRun.typerPhase.id && - fun.symbol == Any_isInstanceOf && !targs.isEmpty) - checkCheckable(tree.pos, targs.head, "") - val resultpe = restpe.instantiateTypeParams(tparams, targs) - //@M substitution in instantiateParams needs to be careful! - //@M example: class Foo[a] { def foo[m[x]]: m[a] = error("") } (new Foo[Int]).foo[List] : List[Int] - //@M --> first, m[a] gets changed to m[Int], then m gets substituted for List, - // this must preserve m's type argument, so that we end up with List[Int], and not List[a] - //@M related bug: #1438 - //println("instantiating type params "+restpe+" "+tparams+" "+targs+" = "+resultpe) - treeCopy.TypeApply(tree, fun, args) setType resultpe - } - } else { - errorTree(tree, "wrong number of type parameters for "+treeSymTypeMsg(fun)) - } - case ErrorType => - setError(tree) - case _ => - errorTree(tree, treeSymTypeMsg(fun)+" does not take type parameters.") - } - /** * @param args ... * @return ... @@ -3922,7 +3923,7 @@ trait Typers { self: Analyzer => } //@M TODO: context.undetparams = undets_fun ? - typedTypeApply(fun1, args1) + typedTypeApply(tree, mode, fun1, args1) case Apply(Block(stats, expr), args) => typed1(atPos(tree.pos)(Block(stats, Apply(expr, args))), mode, pt) diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index a906aa40c3..a6b0a1244d 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -90,7 +90,7 @@ object ClassPath { } /** - * A represents classes which can be loaded with a ClassfileLoader/MSILTypeLoader + * Represents classes which can be loaded with a ClassfileLoader/MSILTypeLoader * and / or a SourcefileLoader. */ case class ClassRep[T](binary: Option[T], source: Option[AbstractFile]) { @@ -124,9 +124,9 @@ abstract class ClassPath[T] { * The short name of the package (without prefix) */ def name: String - def classes: List[ClassRep[T]] - def packages: List[ClassPath[T]] - def sourcepaths: List[AbstractFile] + val classes: List[ClassRep[T]] + val packages: List[ClassPath[T]] + val sourcepaths: List[AbstractFile] /** * Find a ClassRep given a class name of the form "package.subpackage.ClassName". @@ -150,7 +150,7 @@ abstract class ClassPath[T] { class SourcePath[T](dir: AbstractFile) extends ClassPath[T] { def name = dir.name - def classes = { + lazy val classes = { val cls = new ListBuffer[ClassRep[T]] for (f <- dir.iterator) { if (!f.isDirectory && ClassPath.validSourceFile(f.name)) @@ -159,7 +159,7 @@ class SourcePath[T](dir: AbstractFile) extends ClassPath[T] { cls.toList } - def packages = { + lazy val packages = { val pkg = new ListBuffer[SourcePath[T]] for (f <- dir.iterator) { if (f.isDirectory && ClassPath.validPackage(f.name)) @@ -168,7 +168,7 @@ class SourcePath[T](dir: AbstractFile) extends ClassPath[T] { pkg.toList } - def sourcepaths: List[AbstractFile] = List(dir) + val sourcepaths: List[AbstractFile] = List(dir) override def toString() = "sourcepath: "+ dir.toString() } @@ -179,7 +179,7 @@ class SourcePath[T](dir: AbstractFile) extends ClassPath[T] { class DirectoryClassPath(dir: AbstractFile) extends ClassPath[AbstractFile] { def name = dir.name - def classes = { + lazy val classes = { val cls = new ListBuffer[ClassRep[AbstractFile]] for (f <- dir.iterator) { if (!f.isDirectory && ClassPath.validClassFile(f.name)) @@ -188,7 +188,7 @@ class DirectoryClassPath(dir: AbstractFile) extends ClassPath[AbstractFile] { cls.toList } - def packages = { + lazy val packages = { val pkg = new ListBuffer[DirectoryClassPath] for (f <- dir.iterator) { if (f.isDirectory && ClassPath.validPackage(f.name)) @@ -197,7 +197,7 @@ class DirectoryClassPath(dir: AbstractFile) extends ClassPath[AbstractFile] { pkg.toList } - def sourcepaths: List[AbstractFile] = Nil + val sourcepaths: List[AbstractFile] = Nil override def toString() = "directory classpath: "+ dir.toString() } @@ -230,7 +230,7 @@ class AssemblyClassPath(types: Array[MSILType], namespace: String) extends Class if (types(m).FullName.startsWith(namespace)) m else types.length } - def classes = { + lazy val classes = { val cls = new ListBuffer[ClassRep[MSILType]] var i = first while (i < types.length && types(i).Namespace.startsWith(namespace)) { @@ -242,7 +242,7 @@ class AssemblyClassPath(types: Array[MSILType], namespace: String) extends Class cls.toList } - def packages = { + lazy val packages = { val nsSet = new MutHashSet[String] var i = first while (i < types.length && types(i).Namespace.startsWith(namespace)) { @@ -260,7 +260,7 @@ class AssemblyClassPath(types: Array[MSILType], namespace: String) extends Class yield new AssemblyClassPath(types, ns) } - def sourcepaths: List[AbstractFile] = Nil + val sourcepaths: List[AbstractFile] = Nil override def toString() = "assembly classpath "+ namespace } @@ -273,7 +273,7 @@ abstract class MergedClassPath[T] extends ClassPath[T] { def name = entries.head.name - def classes: List[ClassRep[T]] = { + lazy val classes: List[ClassRep[T]] = { val cls = new ListBuffer[ClassRep[T]] for (e <- entries; c <- e.classes) { val name = c.name @@ -291,7 +291,7 @@ abstract class MergedClassPath[T] extends ClassPath[T] { cls.toList } - def packages: List[ClassPath[T]] = { + lazy val packages: List[ClassPath[T]] = { val pkg = new ListBuffer[ClassPath[T]] for (e <- entries; p <- e.packages) { val name = p.name @@ -305,7 +305,7 @@ abstract class MergedClassPath[T] extends ClassPath[T] { pkg.toList } - def sourcepaths: List[AbstractFile] = entries.flatMap(_.sourcepaths) + lazy val sourcepaths: List[AbstractFile] = entries.flatMap(_.sourcepaths) private def addPackage(to: ClassPath[T], pkg: ClassPath[T]) = to match { case cp: MergedClassPath[_] => diff --git a/src/compiler/scala/tools/nsc/util/Statistics.scala b/src/compiler/scala/tools/nsc/util/Statistics.scala index eb8a25a6ed..188f2fcdb2 100644 --- a/src/compiler/scala/tools/nsc/util/Statistics.scala +++ b/src/compiler/scala/tools/nsc/util/Statistics.scala @@ -10,35 +10,53 @@ package util object Statistics { - var enabled = false + private var _enabled = false + + def enabled = _enabled + def enabled_=(cond: Boolean) = { + if (cond && !_enabled) { + val test = new Timer() + val start = System.nanoTime() + var total = 0L + for (i <- 1 to 10000) { + val time = System.nanoTime() + total += System.nanoTime() - time + } + val total2 = System.nanoTime() - start + println("Enabling statistics, measuring overhead = "+ + total/10000.0+"ns to "+total2/10000.0+"ns per timer") + _enabled = true + } + } + var phasesShown = List("parser", "typer", "erasure", "cleanup") def currentTime() = - if (enabled) System.nanoTime() else 0L + if (_enabled) System.nanoTime() else 0L private def showPercent(x: Double, base: Double) = if (base == 0) "" else " ("+"%2.1f".format(x / base * 100)+"%)" def incCounter(c: Counter) { - if (enabled) c.value += 1 + if (_enabled) c.value += 1 } def incCounter(c: Counter, delta: Int) { - if (enabled) c.value += delta + if (_enabled) c.value += delta } def startCounter(sc: SubCounter): IntPair = - if (enabled) sc.start() else null + if (_enabled) sc.start() else null def stopCounter(sc: SubCounter, start: IntPair) { - if (enabled) sc.stop(start) + if (_enabled) sc.stop(start) } def startTimer(tm: Timer): LongPair = - if (enabled) tm.start() else null + if (_enabled) tm.start() else null def stopTimer(tm: Timer, start: LongPair) { - if (enabled) tm.stop(start) + if (_enabled) tm.stop(start) } case class IntPair(x: Int, y: Int) @@ -52,9 +70,9 @@ object Statistics { class SubCounter(c: Counter) { var value: Int = 0 def start(): IntPair = - if (enabled) IntPair(value, c.value) else null + if (_enabled) IntPair(value, c.value) else null def stop(prev: IntPair) { - if (enabled) { + if (_enabled) { val IntPair(value0, cvalue0) = prev value = value0 + c.value - cvalue0 } @@ -64,16 +82,21 @@ object Statistics { } class Timer { - var nanos: Long = 0L + var nanos: Long = 0 + var timings = 0 def start(): LongPair = - if (enabled) LongPair(nanos, System.nanoTime()) else null + if (_enabled) { + timings += 1 + LongPair(nanos, System.nanoTime()) + } else null def stop(prev: LongPair) { - if (enabled) { + if (_enabled) { val LongPair(nanos0, start) = prev nanos = nanos0 + System.nanoTime() - start + timings += 1 } } - override def toString = nanos.toString+"ns" + override def toString = (timings/2)+" spans, "+nanos.toString+"ns" } class ClassCounts extends scala.collection.mutable.HashMap[Class[_], Int] { @@ -82,6 +105,11 @@ object Statistics { var nodeByType = new ClassCounts + var microsByType = new ClassCounts + var visitsByType = new ClassCounts + var pendingTreeTypes: List[Class[_]] = List() + var typerTime: Long = 0L + val singletonBaseTypeSeqCount = new Counter val compoundBaseTypeSeqCount = new Counter val typerefBaseTypeSeqCount = new Counter @@ -137,8 +165,11 @@ object Statistics { val subtypeImprovCount = new SubCounter(subtypeCount) val subtypeETNanos = new Timer val matchesPtNanos = new Timer - val counter1: SubCounter = new SubCounter(findMemberCount) - val counter2: SubCounter = new SubCounter(findMemberCount) + val ctr1 = new Counter + val ctr2 = new Counter + val ctr3 = new Counter + val counter1: SubCounter = new SubCounter(subtypeCount) + val counter2: SubCounter = new SubCounter(subtypeCount) val timer1: Timer = new Timer val timer2: Timer = new Timer } @@ -159,7 +190,7 @@ abstract class Statistics { value+showPercent(value, base) def showRelTyper(timer: Timer) = - timer.nanos+"ns"+showPercent(timer.nanos, typerNanos.nanos) + timer+showPercent(timer.nanos, typerNanos.nanos) def showCounts(counts: ClassCounts) = counts.toSeq.sortWith(_._2 > _._2).map { @@ -219,6 +250,11 @@ abstract class Statistics { inform("time spent in failed : "+showRelTyper(failedSilentNanos)) inform(" failed apply : "+showRelTyper(failedApplyNanos)) inform(" failed op= : "+showRelTyper(failedOpEqNanos)) + inform("micros by tree node : "+showCounts(microsByType)) + inform("#visits by tree node : "+showCounts(visitsByType)) + val average = new ClassCounts + for (c <- microsByType.keysIterator) average(c) = microsByType(c)/visitsByType(c) + inform("avg micros by tree node : "+showCounts(average)) inform("time spent in <:< : "+showRelTyper(subtypeNanos)) inform("time spent in findmember : "+showRelTyper(findMemberNanos)) inform("time spent in asSeenFrom : "+showRelTyper(asSeenFromNanos)) @@ -229,6 +265,9 @@ abstract class Statistics { inform("#implicit oftype hits : " + oftypeImplicitHits) } + if (ctr1 != null) inform("#ctr1 : " + ctr1) + if (ctr2 != null) inform("#ctr2 : " + ctr2) + if (ctr3 != null) inform("#ctr3 : " + ctr3) if (counter1 != null) inform("#counter1 : " + counter1) if (counter2 != null) inform("#counter2 : " + counter2) if (timer1 != null) inform("#timer1 : " + timer1) diff --git a/src/library/scala/Option.scala b/src/library/scala/Option.scala index 6cb0fec929..8511fa78a5 100644 --- a/src/library/scala/Option.scala +++ b/src/library/scala/Option.scala @@ -110,7 +110,7 @@ sealed abstract class Option[+A] extends Product { * * @param pf the partial function. */ - def partialMap[B](pf: A =>? B): Option[B] = + def partialMap[B](pf: PartialFunction[A, B]): Option[B] = if (!isEmpty && pf.isDefinedAt(this.get)) Some(pf(this.get)) else None /** If the option is nonempty return it, diff --git a/src/library/scala/PartialFunction.scala b/src/library/scala/PartialFunction.scala index f62fa68565..f450596e57 100644 --- a/src/library/scala/PartialFunction.scala +++ b/src/library/scala/PartialFunction.scala @@ -38,7 +38,7 @@ trait PartialFunction[-A, +B] extends (A => B) { * of this partial function and `that`. The resulting partial function * takes `x` to `this(x)` where `this` is defined, and to `that(x)` where it is not. */ - def orElse[A1 <: A, B1 >: B](that: A1 =>? B1) : A1 =>? B1 = + def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]) : PartialFunction[A1, B1] = new PartialFunction[A1, B1] { def isDefinedAt(x: A1): Boolean = PartialFunction.this.isDefinedAt(x) || that.isDefinedAt(x) @@ -54,7 +54,7 @@ trait PartialFunction[-A, +B] extends (A => B) { * @return a partial function with the same domain as this partial function, which maps * arguments `x` to `k(this(x))`. */ - override def andThen[C](k: B => C): A =>? C = new PartialFunction[A, C] { + override def andThen[C](k: B => C) : PartialFunction[A, C] = new PartialFunction[A, C] { def isDefinedAt(x: A): Boolean = PartialFunction.this.isDefinedAt(x) def apply(x: A): C = k(PartialFunction.this.apply(x)) } @@ -92,7 +92,7 @@ object PartialFunction * @param pf the partial function * @return true, iff `x` is in the domain of `pf` and `pf(x) == true`. */ - def cond[T](x: T)(pf: T =>? Boolean): Boolean = + def cond[T](x: T)(pf: PartialFunction[T, Boolean]): Boolean = (pf isDefinedAt x) && pf(x) /** Transforms a PartialFunction[T, U] `pf' into Function1[T, Option[U]] `f' @@ -104,6 +104,6 @@ object PartialFunction * @param pf the PartialFunction[T, U] * @return `Some(pf(x))` if `pf isDefinedAt x`, `None` otherwise. */ - def condOpt[T,U](x: T)(pf: T =>? U): Option[U] = + def condOpt[T,U](x: T)(pf: PartialFunction[T, U]): Option[U] = if (pf isDefinedAt x) Some(pf(x)) else None } diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala index 1b9f4b75ba..5684c91aaa 100644 --- a/src/library/scala/Predef.scala +++ b/src/library/scala/Predef.scala @@ -117,7 +117,7 @@ object Predef extends LowPriorityImplicits { throw new IllegalArgumentException("requirement failed: "+ message) } - class Ensuring[A](x: A) { + final class Ensuring[A](val x: A) { def ensuring(cond: Boolean): A = { assert(cond); x } def ensuring(cond: Boolean, msg: Any): A = { assert(cond, msg); x } def ensuring(cond: A => Boolean): A = { assert(cond(x)); x } @@ -139,7 +139,7 @@ object Predef extends LowPriorityImplicits { def unapply[A, B, C](x: Tuple3[A, B, C]): Option[Tuple3[A, B, C]] = Some(x) } - class ArrowAssoc[A](x: A) { + final class ArrowAssoc[A](val x: A) { @inline def -> [B](y: B): Tuple2[A, B] = Tuple2(x, y) def →[B](y: B): Tuple2[A, B] = ->(y) } diff --git a/src/library/scala/collection/IndexedSeqViewLike.scala b/src/library/scala/collection/IndexedSeqViewLike.scala index 06fa6c8953..07f63ad2b0 100644 --- a/src/library/scala/collection/IndexedSeqViewLike.scala +++ b/src/library/scala/collection/IndexedSeqViewLike.scala @@ -24,28 +24,55 @@ import TraversableView.NoBuilder trait IndexedSeqViewLike[+A, +Coll, +This <: IndexedSeqView[A, Coll] with IndexedSeqViewLike[A, Coll, This]] - extends IndexedSeq[A] - with IndexedSeqLike[A, This] - with SeqView[A, Coll] - with SeqViewLike[A, Coll, This] - with views.IndexedSeqTransformations[A, Coll, This] + extends IndexedSeq[A] with IndexedSeqLike[A, This] with SeqView[A, Coll] with SeqViewLike[A, Coll, This] { self => - trait Transformed[+B] extends views.IndexedSeqLike[B, Coll] with super.Transformed[B] + trait Transformed[+B] extends IndexedSeqView[B, Coll] with super.Transformed[B] - trait Sliced extends Transformed[A] with super.Sliced - trait Mapped[B] extends Transformed[B] with super.Mapped[B] - trait FlatMapped[B] extends Transformed[B] with super.FlatMapped[B] - trait Appended[B >: A] extends Transformed[B] with super.Appended[B] - trait Filtered extends Transformed[A] with super.Filtered - trait TakenWhile extends Transformed[A] with super.TakenWhile - trait DroppedWhile extends Transformed[A] with super.DroppedWhile - trait Reversed extends Transformed[A] with super.Reversed - trait Patched[B >: A] extends Transformed[B] with super.Patched[B] + trait Sliced extends Transformed[A] with super.Sliced { + /** Override to use IndexedSeq's foreach; todo: see whether this is really faster */ + override def foreach[U](f: A => U) = super[Transformed].foreach(f) + } + + trait Mapped[B] extends Transformed[B] with super.Mapped[B] { + override def foreach[U](f: B => U) = super[Transformed].foreach(f) + } + + trait FlatMapped[B] extends Transformed[B] with super.FlatMapped[B] { + override def foreach[U](f: B => U) = super[Transformed].foreach(f) + } + + trait Appended[B >: A] extends Transformed[B] with super.Appended[B] { + override def foreach[U](f: B => U) = super[Transformed].foreach(f) + } + + trait Filtered extends Transformed[A] with super.Filtered { + override def foreach[U](f: A => U) = super[Transformed].foreach(f) + } + + trait TakenWhile extends Transformed[A] with super.TakenWhile { + override def foreach[U](f: A => U) = super[Transformed].foreach(f) + } + + trait DroppedWhile extends Transformed[A] with super.DroppedWhile { + override def foreach[U](f: A => U) = super[Transformed].foreach(f) + } + + trait Reversed extends Transformed[A] with super.Reversed { + override def foreach[U](f: A => U) = super[Transformed].foreach(f) + } + + trait Patched[B >: A] extends Transformed[B] with super.Patched[B] { + override def foreach[U](f: B => U) = super[Transformed].foreach(f) + } trait Zipped[B] extends Transformed[(A, B)] { protected[this] val other: Iterable[B] - def length = self.length min other.size + /** Have to be careful here - other may be an infinite sequence. */ + def length = + if (other.hasDefiniteSize) self.length min other.size + else other take self.length size + def apply(idx: Int): (A, B) = (self.apply(idx), other.iterator drop idx next) override def stringPrefix = self.stringPrefix+"Z" } @@ -65,5 +92,22 @@ trait IndexedSeqViewLike[+A, } override def stringPrefix = self.stringPrefix+"Z" } + + /** Boilerplate method, to override in each subclass + * This method could be eliminated if Scala had virtual classes + */ + protected override def newAppended[B >: A](that: Traversable[B]): Transformed[B] = new Appended[B] { val rest = that } + protected override def newMapped[B](f: A => B): Transformed[B] = new Mapped[B] { val mapping = f } + protected override def newFlatMapped[B](f: A => Traversable[B]): Transformed[B] = new FlatMapped[B] { val mapping = f } + protected override def newFiltered(p: A => Boolean): Transformed[A] = new Filtered { val pred = p } + protected override def newSliced(_from: Int, _until: Int): Transformed[A] = new Sliced { val from = _from; val until = _until } + protected override def newDroppedWhile(p: A => Boolean): Transformed[A] = new DroppedWhile { val pred = p } + protected override def newTakenWhile(p: A => Boolean): Transformed[A] = new TakenWhile { val pred = p } + protected override def newZipped[B](that: Iterable[B]): Transformed[(A, B)] = new Zipped[B] { val other = that } + protected override def newZippedAll[A1 >: A, B](that: Iterable[B], _thisElem: A1, _thatElem: B): Transformed[(A1, B)] = new ZippedAll[A1, B] { val other = that; val thisElem = _thisElem; val thatElem = _thatElem } + protected override def newReversed: Transformed[A] = new Reversed { } + protected override def newPatched[B >: A](_from: Int, _patch: Seq[B], _replaced: Int): Transformed[B] = new Patched[B] { + val from = _from; val patch = _patch; val replaced = _replaced + } override def stringPrefix = "IndexedSeqView" } diff --git a/src/library/scala/collection/IterableViewLike.scala b/src/library/scala/collection/IterableViewLike.scala index 831a244352..27323294c4 100644 --- a/src/library/scala/collection/IterableViewLike.scala +++ b/src/library/scala/collection/IterableViewLike.scala @@ -24,14 +24,10 @@ import TraversableView.NoBuilder trait IterableViewLike[+A, +Coll, +This <: IterableView[A, Coll] with IterableViewLike[A, Coll, This]] - extends Iterable[A] - with IterableLike[A, This] - with TraversableView[A, Coll] - with TraversableViewLike[A, Coll, This] - with views.IterableTransformations[A, Coll, This] +extends Iterable[A] with IterableLike[A, This] with TraversableView[A, Coll] with TraversableViewLike[A, Coll, This] { self => - trait Transformed[+B] extends views.IterableLike[B, Coll] with super.Transformed[B] + trait Transformed[+B] extends IterableView[B, Coll] with super.Transformed[B] trait Sliced extends Transformed[A] with super.Sliced { override def iterator = self.iterator slice (from, until) @@ -88,5 +84,25 @@ trait IterableViewLike[+A, override def zipAll[B, A1 >: A, That](that: Iterable[B], thisElem: A1, thatElem: B)(implicit bf: CanBuildFrom[This, (A1, B), That]): That = newZippedAll(that, thisElem, thatElem).asInstanceOf[That] + protected def newZipped[B](that: Iterable[B]): Transformed[(A, B)] = new Zipped[B] { + val other = that + } + protected def newZippedAll[A1 >: A, B](that: Iterable[B], _thisElem: A1, _thatElem: B): Transformed[(A1, B)] = new ZippedAll[A1, B] { + val other: Iterable[B] = that + val thisElem = _thisElem + val thatElem = _thatElem + } + + /** Boilerplate method, to override in each subclass + * This method could be eliminated if Scala had virtual classes + */ + protected override def newAppended[B >: A](that: Traversable[B]): Transformed[B] = new Appended[B] { val rest = that } + protected override def newMapped[B](f: A => B): Transformed[B] = new Mapped[B] { val mapping = f } + protected override def newFlatMapped[B](f: A => Traversable[B]): Transformed[B] = new FlatMapped[B] { val mapping = f } + protected override def newFiltered(p: A => Boolean): Transformed[A] = new Filtered { val pred = p } + protected override def newSliced(_from: Int, _until: Int): Transformed[A] = new Sliced { val from = _from; val until = _until } + protected override def newDroppedWhile(p: A => Boolean): Transformed[A] = new DroppedWhile { val pred = p } + protected override def newTakenWhile(p: A => Boolean): Transformed[A] = new TakenWhile { val pred = p } + override def stringPrefix = "IterableView" } diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala index 5f28161ed3..c23765c9bc 100644 --- a/src/library/scala/collection/Iterator.scala +++ b/src/library/scala/collection/Iterator.scala @@ -411,7 +411,7 @@ trait Iterator[+A] { self => * @return a new iterator which yields each value `x` produced by this iterator for * which `pf` is defined the image `pf(x)`. */ - def partialMap[B](pf: A =>? B): Iterator[B] = { + def partialMap[B](pf: PartialFunction[A, B]): Iterator[B] = { val self = buffered new Iterator[B] { private def skip() = while (self.hasNext && !pf.isDefinedAt(self.head)) self.next() @@ -1112,9 +1112,10 @@ trait Iterator[+A] { self => res.toList } - /** Traverses this iterator and returns all produced values in a list. + /** Lazily wraps a Stream around this iterator so its values are memoized. * - * @return a stream which contains all values produced by this iterator. + * @return a Stream which can repeatedly produce all the values + * produced by this iterator. */ def toStream: Stream[A] = if (hasNext) Stream.cons(next, toStream) else Stream.empty diff --git a/src/library/scala/collection/JavaConversions.scala b/src/library/scala/collection/JavaConversions.scala index 15005f71ba..7af138067b 100644 --- a/src/library/scala/collection/JavaConversions.scala +++ b/src/library/scala/collection/JavaConversions.scala @@ -53,6 +53,7 @@ package scala.collection */ object JavaConversions { import java.{ lang => jl, util => ju } + import java.util.{ concurrent => juc } import scala.collection.{ generic, immutable, mutable, Traversable } import scala.reflect.ClassManifest @@ -178,10 +179,17 @@ object JavaConversions { * @return A Java <code>Map</code> view of the argument. */ implicit def asMap[A, B](m : mutable.Map[A, B])(implicit ma : ClassManifest[A]) : ju.Map[A, B] = m match { + //case JConcurrentMapWrapper(wrapped) => wrapped case JMapWrapper(wrapped) => wrapped case _ => new MutableMapWrapper(m)(ma) } + implicit def asConcurrentMap[A, B](m: mutable.ConcurrentMap[A, B]) + (implicit ma: ClassManifest[A], mb: ClassManifest[B]): juc.ConcurrentMap[A, B] = m match { + case JConcurrentMapWrapper(wrapped) => wrapped + case _ => new ConcurrentMapWrapper(m)(ma, mb) + } + // Java => Scala /** @@ -303,8 +311,31 @@ object JavaConversions { * @return A Scala mutable <code>Map</code> view of the argument. */ implicit def asMap[A, B](m : ju.Map[A, B]) = m match { + //case ConcurrentMapWrapper(wrapped) => wrapped case MutableMapWrapper(wrapped) => wrapped - case _ =>new JMapWrapper(m) + case _ => new JMapWrapper(m) + } + + /** + * Implicitly converts a Java <code>ConcurrentMap</code> to a Scala mutable <code>ConcurrentMap</code>. + * The returned Scala <code>ConcurrentMap</code> is backed by the provided Java + * <code>ConcurrentMap</code> and any side-effects of using it via the Scala interface will + * be visible via the Java interface and vice versa. + * <p> + * If the Java <code>ConcurrentMap</code> was previously obtained from an implicit or + * explicit call of <code>asConcurrentMap(scala.collection.mutable.ConcurrentMap)</code> then the original + * Scala <code>ConcurrentMap</code> will be returned. + * + * @param m The <code>ConcurrentMap</code> to be converted. + * @return A Scala mutable <code>ConcurrrentMap</code> view of the argument. + */ + implicit def asConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]) = m match { + case ConcurrentMapWrapper(wrapped) => wrapped + case _ => new JConcurrentMapWrapper(m) + } + + implicit def asMap(p: ju.Properties): mutable.Map[String, String] = p match { + case _ => new JPropertiesWrapper(p) } // Private implementations ... @@ -410,7 +441,8 @@ object JavaConversions { override def empty = JSetWrapper(new ju.HashSet[A]) } - case class MutableMapWrapper[A, B](underlying : mutable.Map[A, B])(m : ClassManifest[A]) extends ju.AbstractMap[A, B] { + abstract class MutableMapWrapperLike[A, B](underlying: mutable.Map[A, B])(m: ClassManifest[A]) + extends ju.AbstractMap[A, B] { self => override def size = underlying.size @@ -462,7 +494,12 @@ object JavaConversions { } } - case class JMapWrapper[A, B](underlying : ju.Map[A, B]) extends mutable.Map[A, B] with mutable.MapLike[A, B, JMapWrapper[A, B]] { + case class MutableMapWrapper[A, B](underlying : mutable.Map[A, B])(m : ClassManifest[A]) + extends MutableMapWrapperLike[A, B](underlying)(m) + + abstract class JMapWrapperLike[A, B, +Repr <: mutable.MapLike[A, B, Repr] with mutable.Map[A, B]] + (underlying: ju.Map[A, B]) + extends mutable.Map[A, B] with mutable.MapLike[A, B, Repr] { override def size = underlying.size def get(k : A) = { @@ -498,6 +535,127 @@ object JavaConversions { override def clear = underlying.clear + override def empty: Repr = null.asInstanceOf[Repr] + } + + case class JMapWrapper[A, B](underlying : ju.Map[A, B]) + extends JMapWrapperLike[A, B, JMapWrapper[A, B]](underlying) { override def empty = JMapWrapper(new ju.HashMap[A, B]) } + + case class ConcurrentMapWrapper[A, B](underlying: mutable.ConcurrentMap[A, B]) + (m: ClassManifest[A], mv: ClassManifest[B]) + extends MutableMapWrapperLike[A, B](underlying)(m) with juc.ConcurrentMap[A, B] { + self => + + override def remove(k : AnyRef) = { + if (!m.erasure.isInstance(k)) + null.asInstanceOf[B] + else { + val k1 = k.asInstanceOf[A] + underlying.remove(k1) match { + case Some(v) => v + case None => null.asInstanceOf[B] + } + } + } + + def putIfAbsent(k: A, v: B) = underlying.putIfAbsent(k, v) match { + case Some(v) => v + case None => null.asInstanceOf[B] + } + + def remove(k: AnyRef, v: AnyRef) = { + if (!m.erasure.isInstance(k) || !mv.erasure.isInstance(v)) + false + else { + val k1 = k.asInstanceOf[A] + val v1 = v.asInstanceOf[B] + underlying.remove(k1, v1) + } + } + + def replace(k: A, v: B): B = underlying.replace(k, v) match { + case Some(v) => v + case None => null.asInstanceOf[B] + } + + def replace(k: A, oldval: B, newval: B) = underlying.replace(k, oldval, newval) + + } + + case class JConcurrentMapWrapper[A, B](underlying: juc.ConcurrentMap[A, B]) + extends JMapWrapperLike[A, B, JConcurrentMapWrapper[A, B]](underlying) with mutable.ConcurrentMap[A, B] { + override def get(k: A) = { + val v = underlying.get(k) + if (v != null) Some(v) + else None + } + + override def empty = new JConcurrentMapWrapper(new juc.ConcurrentHashMap[A, B]) + + def putIfAbsent(k: A, v: B): Option[B] = { + val r = underlying.putIfAbsent(k, v) + if (r != null) Some(r) else None + } + + def remove(k: A, v: B): Boolean = underlying.remove(k, v) + + def replace(k: A, v: B): Option[B] = { + val prev = underlying.replace(k, v) + if (prev != null) Some(prev) else None + } + + def replace(k: A, oldvalue: B, newvalue: B): Boolean = underlying.replace(k, oldvalue, newvalue) + + } + + case class JPropertiesWrapper(underlying: ju.Properties) + extends mutable.Map[String, String] with mutable.MapLike[String, String, JPropertiesWrapper] { + override def size = underlying.size + + def get(k : String) = { + val v = underlying.get(k) + if (v != null) + Some(v.asInstanceOf[String]) + else + None + } + + def +=(kv: (String, String)): this.type = { underlying.put(kv._1, kv._2); this } + def -=(key: String): this.type = { underlying.remove(key); this } + + override def put(k : String, v : String): Option[String] = { + val r = underlying.put(k, v) + if (r != null) Some(r.asInstanceOf[String]) else None + } + + override def update(k : String, v : String) { underlying.put(k, v) } + + override def remove(k : String): Option[String] = { + val r = underlying.remove(k) + if (r != null) Some(r.asInstanceOf[String]) else None + } + + def iterator = new Iterator[(String, String)] { + val ui = underlying.entrySet.iterator + def hasNext = ui.hasNext + def next = { val e = ui.next ; (e.getKey.asInstanceOf[String], e.getValue.asInstanceOf[String]) } + } + + override def clear = underlying.clear + + override def empty = JPropertiesWrapper(new ju.Properties) + + def getProperty(key: String) = underlying.getProperty(key) + + def getProperty(key: String, defaultValue: String) = underlying.getProperty(key, defaultValue) + + def setProperty(key: String, value: String) = underlying.setProperty(key, value) + } + } + + + + diff --git a/src/library/scala/collection/SeqViewLike.scala b/src/library/scala/collection/SeqViewLike.scala index 6f677616e7..1a8cd20013 100644 --- a/src/library/scala/collection/SeqViewLike.scala +++ b/src/library/scala/collection/SeqViewLike.scala @@ -23,14 +23,13 @@ import TraversableView.NoBuilder trait SeqViewLike[+A, +Coll, +This <: SeqView[A, Coll] with SeqViewLike[A, Coll, This]] - extends Seq[A] - with SeqLike[A, This] - with IterableView[A, Coll] - with IterableViewLike[A, Coll, This] - with views.SeqTransformations[A, Coll, This] + extends Seq[A] with SeqLike[A, This] with IterableView[A, Coll] with IterableViewLike[A, Coll, This] { self => - trait Transformed[+B] extends views.SeqLike[B, Coll] with super.Transformed[B] + trait Transformed[+B] extends SeqView[B, Coll] with super.Transformed[B] { + override def length: Int + override def apply(idx: Int): B + } trait Sliced extends Transformed[A] with super.Sliced { override def length = ((until min self.length) - from) max 0 @@ -144,6 +143,21 @@ trait SeqViewLike[+A, override def stringPrefix = self.stringPrefix+"P" } + /** Boilerplate method, to override in each subclass + * This method could be eliminated if Scala had virtual classes + */ + protected override def newAppended[B >: A](that: Traversable[B]): Transformed[B] = new Appended[B] { val rest = that } + protected override def newMapped[B](f: A => B): Transformed[B] = new Mapped[B] { val mapping = f } + protected override def newFlatMapped[B](f: A => Traversable[B]): Transformed[B] = new FlatMapped[B] { val mapping = f } + protected override def newFiltered(p: A => Boolean): Transformed[A] = new Filtered { val pred = p } + protected override def newSliced(_from: Int, _until: Int): Transformed[A] = new Sliced { val from = _from; val until = _until } + protected override def newDroppedWhile(p: A => Boolean): Transformed[A] = new DroppedWhile { val pred = p } + protected override def newTakenWhile(p: A => Boolean): Transformed[A] = new TakenWhile { val pred = p } + protected override def newZipped[B](that: Iterable[B]): Transformed[(A, B)] = new Zipped[B] { val other = that } + protected override def newZippedAll[A1 >: A, B](that: Iterable[B], _thisElem: A1, _thatElem: B): Transformed[(A1, B)] = new ZippedAll[A1, B] { val other = that; val thisElem = _thisElem; val thatElem = _thatElem } + protected def newReversed: Transformed[A] = new Reversed { } + protected def newPatched[B >: A](_from: Int, _patch: Seq[B], _replaced: Int): Transformed[B] = new Patched[B] { val from = _from; val patch = _patch; val replaced = _replaced } + override def reverse: This = newReversed.asInstanceOf[This] override def patch[B >: A, That](from: Int, patch: Seq[B], replaced: Int)(implicit bf: CanBuildFrom[This, B, That]): That = { diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala index f570c4ca9a..fc666ddb92 100644 --- a/src/library/scala/collection/TraversableLike.scala +++ b/src/library/scala/collection/TraversableLike.scala @@ -292,13 +292,13 @@ self => * `pf` to each element on which it is defined and collecting the results. * The order of the elements is preserved. * - * @usecase def partialMap[B](pf: A =>? B): $Coll[B] + * @usecase def partialMap[B](pf: PartialFunction[A, B]): $Coll[B] * * @return a new $coll resulting from applying the given partial function * `pf` to each element on which it is defined and collecting the results. * The order of the elements is preserved. */ - def partialMap[B, That](pf: A =>? B)(implicit bf: CanBuildFrom[Repr, B, That]): That = { + def partialMap[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That = { val b = bf(repr) for (x <- this) if (pf.isDefinedAt(x)) b += pf(x) b.result @@ -984,9 +984,7 @@ self => def toList: List[A] = (new ListBuffer[A] ++= thisCollection).toList /** Converts this $coll to an iterable collection. - * - * Note: Will not terminate for infinite-sized collections. - * + * $willNotTerminateInf * @return an `Iterable` containing all elements of this $coll. */ def toIterable: Iterable[A] = toStream @@ -1015,6 +1013,22 @@ self => */ def toSet[B >: A]: immutable.Set[B] = immutable.Set() ++ thisCollection + /** Converts this $coll to a map. This method is unavailable unless + * the elements are members of Tuple2, each ((K, V)) becoming a key-value + * pair in the map. Duplicate keys will be overwritten by later keys: + * if this is an unordered collection, which key is in the resulting map + * is undefined. + * $willNotTerminateInf + * @return a map containing all elements of this $coll. + */ + def toMap[T, U](implicit ev: A <:< (T, U)): immutable.Map[T, U] = { + val b = immutable.Map.newBuilder[T, U] + for (x <- this) + b += x + + b.result + } + /** Displays all elements of this $coll in a string using start, end, and separator strings. * * @param start the starting string. diff --git a/src/library/scala/collection/TraversableProxyLike.scala b/src/library/scala/collection/TraversableProxyLike.scala index d8e3ed2a1b..24d6c7048d 100644 --- a/src/library/scala/collection/TraversableProxyLike.scala +++ b/src/library/scala/collection/TraversableProxyLike.scala @@ -36,7 +36,7 @@ trait TraversableProxyLike[+A, +This <: TraversableLike[A, This] with Traversabl override def ++[B >: A, That](that: Iterator[B])(implicit bf: CanBuildFrom[This, B, That]): That = self.++(that)(bf) override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[This, B, That]): That = self.map(f)(bf) override def flatMap[B, That](f: A => Traversable[B])(implicit bf: CanBuildFrom[This, B, That]): That = self.flatMap(f)(bf) - override def partialMap[B, That](pf: A =>? B)(implicit bf: CanBuildFrom[This, B, That]): That = self.partialMap(pf)(bf) + override def partialMap[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[This, B, That]): That = self.partialMap(pf)(bf) override def filter(p: A => Boolean): This = self.filter(p) override def filterNot(p: A => Boolean): This = self.filterNot(p) override def partition(p: A => Boolean): (This, This) = self.partition(p) diff --git a/src/library/scala/collection/TraversableViewLike.scala b/src/library/scala/collection/TraversableViewLike.scala index 7f4d0ebd71..84c33296db 100644 --- a/src/library/scala/collection/TraversableViewLike.scala +++ b/src/library/scala/collection/TraversableViewLike.scala @@ -33,9 +33,7 @@ import TraversableView.NoBuilder trait TraversableViewLike[+A, +Coll, +This <: TraversableView[A, Coll] with TraversableViewLike[A, Coll, This]] - extends Traversable[A] - with TraversableLike[A, This] - with views.TraversableTransformations[A, Coll, This] { + extends Traversable[A] with TraversableLike[A, This] { self => override protected[this] def newBuilder: Builder[A, This] = @@ -43,16 +41,16 @@ self => protected def underlying: Coll - trait Transformed[+B] extends views.TraversableLike[B, Coll] { - lazy val underlying = self.underlying - } - def force[B >: A, That](implicit bf: CanBuildFrom[Coll, B, That]) = { val b = bf(underlying) b ++= this b.result() } + trait Transformed[+B] extends TraversableView[B, Coll] { + lazy val underlying = self.underlying + } + /** pre: from >= 0 */ trait Sliced extends Transformed[A] { @@ -133,6 +131,17 @@ self => override def stringPrefix = self.stringPrefix+"D" } + /** Boilerplate method, to override in each subclass + * This method could be eliminated if Scala had virtual classes + */ + protected def newAppended[B >: A](that: Traversable[B]): Transformed[B] = new Appended[B] { val rest = that } + protected def newMapped[B](f: A => B): Transformed[B] = new Mapped[B] { val mapping = f } + protected def newFlatMapped[B](f: A => Traversable[B]): Transformed[B] = new FlatMapped[B] { val mapping = f } + protected def newFiltered(p: A => Boolean): Transformed[A] = new Filtered { val pred = p } + protected def newSliced(_from: Int, _until: Int): Transformed[A] = new Sliced { val from = _from; val until = _until } + protected def newDroppedWhile(p: A => Boolean): Transformed[A] = new DroppedWhile { val pred = p } + protected def newTakenWhile(p: A => Boolean): Transformed[A] = new TakenWhile { val pred = p } + override def ++[B >: A, That](that: Traversable[B])(implicit bf: CanBuildFrom[This, B, That]): That = { newAppended(that).asInstanceOf[That] // was: if (bf.isInstanceOf[ByPassCanBuildFrom]) newAppended(that).asInstanceOf[That] diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala index 2c36161003..2088f3ac78 100644 --- a/src/library/scala/collection/immutable/List.scala +++ b/src/library/scala/collection/immutable/List.scala @@ -98,7 +98,7 @@ sealed abstract class List[+A] extends LinearSeq[A] /** Builds a new list by applying a function to all elements of this list. * Like `xs map f`, but returns `xs` unchanged if function - * `f` maps all elements to themselves (wrt ==). + * `f` maps all elements to themselves (wrt eq). * * Note: Unlike `map`, `mapConserve` is not tail-recursive. * @@ -106,15 +106,15 @@ sealed abstract class List[+A] extends LinearSeq[A] * @tparam B the element type of the returned collection. * @return a list resulting from applying the given function * `f` to each element of this list and collecting the results. - * @usecase def mapConserve[B](f: A => B): List[A] + * @usecase def mapConserve(f: A => A): List[A] */ - def mapConserve[B >: A] (f: A => B): List[B] = { + def mapConserve[B >: A <: AnyRef] (f: A => B): List[B] = { def loop(ys: List[A]): List[B] = if (ys.isEmpty) this else { val head0 = ys.head val head1 = f(head0) - if (head1 == head0) { + if (head1 eq head0.asInstanceOf[AnyRef]) { loop(ys.tail) } else { val ys1 = head1 :: ys.tail.mapConserve(f) diff --git a/src/library/scala/collection/immutable/RedBlack.scala b/src/library/scala/collection/immutable/RedBlack.scala index 9fd082a7fd..dfb34552cd 100644 --- a/src/library/scala/collection/immutable/RedBlack.scala +++ b/src/library/scala/collection/immutable/RedBlack.scala @@ -33,7 +33,7 @@ abstract class RedBlack[A] { def isBlack: Boolean def lookup(x: A): Tree[B] def update[B1 >: B](k: A, v: B1): Tree[B1] = blacken(upd(k, v)) - def delete(k: A): Tree[B] = del(k) + def delete(k: A): Tree[B] = blacken(del(k)) def foreach[U](f: (A, B) => U) @deprecated("use `foreach' instead") def visit[T](input: T)(f: (T, A, B) => (Boolean, T)): (Boolean, T) @@ -80,16 +80,77 @@ abstract class RedBlack[A] { else if (isSmaller(key, k)) balanceRight(isBlack, key, value, left, right.upd(k, v)) else mkTree(isBlack, k, v, left, right) } + // Based on Stefan Kahrs' Haskell version of Okasaki's Red&Black Trees + // http://www.cse.unsw.edu.au/~dons/data/RedBlackTree.html def del(k: A): Tree[B] = { - if (isSmaller(k, key)) mkTree(isBlack, key, value, left.del(k), right) - else if (isSmaller(key, k)) mkTree(isBlack, key, value, left, right.del(k)) - else if (left.isEmpty) right - else if (right.isEmpty) left - else { - val s = right.smallest - mkTree(isBlack, s.key, s.value, left, right.del(s.key)) + def balance(x: A, xv: B, tl: Tree[B], tr: Tree[B]) = (tl, tr) match { + case (RedTree(y, yv, a, b), RedTree(z, zv, c, d)) => + RedTree(x, xv, BlackTree(y, yv, a, b), BlackTree(z, zv, c, d)) + case (RedTree(y, yv, RedTree(z, zv, a, b), c), d) => + RedTree(y, yv, BlackTree(z, zv, a, b), BlackTree(x, xv, c, d)) + case (RedTree(y, yv, a, RedTree(z, zv, b, c)), d) => + RedTree(z, zv, BlackTree(y, yv, a, b), BlackTree(x, xv, c, d)) + case (a, RedTree(y, yv, b, RedTree(z, zv, c, d))) => + RedTree(y, yv, BlackTree(x, xv, a, b), BlackTree(z, zv, c, d)) + case (a, RedTree(y, yv, RedTree(z, zv, b, c), d)) => + RedTree(z, zv, BlackTree(x, xv, a, b), BlackTree(y, yv, c, d)) + case (a, b) => + BlackTree(x, xv, a, b) + } + def subl(t: Tree[B]) = t match { + case BlackTree(x, xv, a, b) => RedTree(x, xv, a, b) + case _ => error("Defect: invariance violation; expected black, got "+t) + } + def balLeft(x: A, xv: B, tl: Tree[B], tr: Tree[B]) = (tl, tr) match { + case (RedTree(y, yv, a, b), c) => + RedTree(x, xv, BlackTree(y, yv, a, b), c) + case (bl, BlackTree(y, yv, a, b)) => + balance(x, xv, bl, RedTree(y, yv, a, b)) + case (bl, RedTree(y, yv, BlackTree(z, zv, a, b), c)) => + RedTree(z, zv, BlackTree(x, xv, bl, a), balance(y, yv, b, subl(c))) + case _ => error("Defect: invariance violation at "+right) + } + def balRight(x: A, xv: B, tl: Tree[B], tr: Tree[B]) = (tl, tr) match { + case (a, RedTree(y, yv, b, c)) => + RedTree(x, xv, a, BlackTree(y, yv, b, c)) + case (BlackTree(y, yv, a, b), bl) => + balance(x, xv, RedTree(y, yv, a, b), bl) + case (RedTree(y, yv, a, BlackTree(z, zv, b, c)), bl) => + RedTree(z, zv, balance(y, yv, subl(a), b), BlackTree(x, xv, c, bl)) + case _ => error("Defect: invariance violation at "+left) + } + def delLeft = left match { + case _: BlackTree[_] => balLeft(key, value, left.del(k), right) + case _ => RedTree(key, value, left.del(k), right) + } + def delRight = right match { + case _: BlackTree[_] => balRight(key, value, left, right.del(k)) + case _ => RedTree(key, value, left, right.del(k)) + } + def append(tl: Tree[B], tr: Tree[B]): Tree[B] = (tl, tr) match { + case (Empty, t) => t + case (t, Empty) => t + case (RedTree(x, xv, a, b), RedTree(y, yv, c, d)) => + append(b, c) match { + case RedTree(z, zv, bb, cc) => RedTree(z, zv, RedTree(x, xv, a, bb), RedTree(y, yv, cc, d)) + case bc => RedTree(x, xv, a, RedTree(y, yv, bc, d)) + } + case (BlackTree(x, xv, a, b), BlackTree(y, yv, c, d)) => + append(b, c) match { + case RedTree(z, zv, bb, cc) => RedTree(z, zv, BlackTree(x, xv, a, bb), BlackTree(y, yv, cc, d)) + case bc => balLeft(x, xv, a, BlackTree(y, yv, bc, d)) + } + case (a, RedTree(x, xv, b, c)) => RedTree(x, xv, append(a, b), c) + case (RedTree(x, xv, a, b), c) => RedTree(x, xv, a, append(b, c)) + } + // RedBlack is neither A : Ordering[A], nor A <% Ordered[A] + k match { + case _ if isSmaller(k, key) => delLeft + case _ if isSmaller(key, k) => delRight + case _ => append(left, right) } } + def smallest: NonEmpty[B] = if (left.isEmpty) this else left.smallest def toStream: Stream[(A,B)] = diff --git a/src/library/scala/collection/immutable/StringOps.scala b/src/library/scala/collection/immutable/StringOps.scala index 9138c2bbac..95509ab9d6 100644 --- a/src/library/scala/collection/immutable/StringOps.scala +++ b/src/library/scala/collection/immutable/StringOps.scala @@ -17,7 +17,7 @@ import mutable.StringBuilder /** * @since 2.8 */ -class StringOps(override val repr: String) extends StringLike[String] { +final class StringOps(override val repr: String) extends StringLike[String] { override protected[this] def thisCollection: WrappedString = new WrappedString(repr) override protected[this] def toCollection(repr: String): WrappedString = new WrappedString(repr) @@ -25,5 +25,8 @@ class StringOps(override val repr: String) extends StringLike[String] { /** Creates a string builder buffer as builder for this class */ override protected[this] def newBuilder = new StringBuilder + override def slice(from: Int, until: Int): String = + repr.substring(from max 0, until min repr.length) + override def toString = repr } diff --git a/src/library/scala/collection/immutable/WrappedString.scala b/src/library/scala/collection/immutable/WrappedString.scala index e535cddfce..e10b3ab0ee 100644 --- a/src/library/scala/collection/immutable/WrappedString.scala +++ b/src/library/scala/collection/immutable/WrappedString.scala @@ -26,6 +26,9 @@ class WrappedString(override val self: String) extends IndexedSeq[Char] with Str /** Creates a string builder buffer as builder for this class */ override protected[this] def newBuilder = WrappedString.newBuilder + + override def slice(from: Int, until: Int): WrappedString = + new WrappedString(self.substring(from max 0, until min self.length)) } /** diff --git a/src/library/scala/collection/interfaces/TraversableMethods.scala b/src/library/scala/collection/interfaces/TraversableMethods.scala index 4cf133d36a..08ade7586d 100644 --- a/src/library/scala/collection/interfaces/TraversableMethods.scala +++ b/src/library/scala/collection/interfaces/TraversableMethods.scala @@ -24,7 +24,7 @@ trait TraversableMethods[+A, +This <: TraversableLike[A, This] with Traversable[ // maps/iteration def flatMap[B, That](f: A => Traversable[B])(implicit bf: CanBuildFrom[This, B, That]): That def map[B, That](f: A => B)(implicit bf: CanBuildFrom[This, B, That]): That - def partialMap[B, That](pf: A =>? B)(implicit bf: CanBuildFrom[This, B, That]): That + def partialMap[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[This, B, That]): That // new collections def ++[B >: A, That](that: Iterator[B])(implicit bf: CanBuildFrom[This, B, That]): That diff --git a/src/library/scala/collection/mutable/ConcurrentMap.scala b/src/library/scala/collection/mutable/ConcurrentMap.scala new file mode 100644 index 0000000000..d09bf57e1b --- /dev/null +++ b/src/library/scala/collection/mutable/ConcurrentMap.scala @@ -0,0 +1,79 @@ +package scala.collection.mutable + + + + + + +/** + * A template trait for mutable maps that allow concurrent access. + * $concurrentmapinfo + * + * @tparam A the key type of the map + * @tparam B the value type of the map + * + * @define concurrentmapinfo + * This is a base trait for all Scala concurrent map implementations. It + * provides all of the methods a Map does, with the difference that all the + * changes are atomic. It also describes methods specific to concurrent maps. + * Note: The concurrent maps do not accept `null` for keys or values. + * + * @define atomicop + * This is done atomically. + * + * @since 2.8 + */ +trait ConcurrentMap[A, B] extends Map[A, B] { + + /** + * Associates the given key with a given value, unless the key was already associated with some other value. + * $atomicop + * + * @param k key with which the specified value is to be associated with + * @param v value to be associated with the specified key + * @return `Some(oldvalue)` if there was a value `oldvalue` previously associated with the + * specified key, or `None` if there was no mapping for the specified key + */ + def putIfAbsent(k: A, v: B): Option[B] + + /** + * Removes the entry for the specified key if its currently mapped to the specified value. + * $atomicop + * + * @param k key for which the entry should be removed + * @param v value expected to be associated with the specified key if the removal is to take place + * @return `true` if the removal took place, `false` otherwise + */ + def remove(k: A, v: B): Boolean + + /** + * Replaces the entry for the given key only if it was previously mapped to a given value. + * $atomicop + * + * @param k key for which the entry should be replaced + * @param oldvalue value expected to be associated with the specified key if replacing is to happen + * @param newvalue value to be associated with the specified key + * @return `true` if the entry was replaced, `false` otherwise + */ + def replace(k: A, oldvalue: B, newvalue: B): Boolean + + /** + * Replaces the entry for the given key only if it was previously mapped to some value. + * $atomicop + * + * @param k key for which the entry should be replaced + * @param v value to be associated with the specified key + * @return `Some(v)` if the given key was previously mapped to some value `v`, or `None` otherwise + */ + def replace(k: A, v: B): Option[B] + +} + + + + + + + + + diff --git a/src/library/scala/collection/mutable/FlatHashTable.scala b/src/library/scala/collection/mutable/FlatHashTable.scala index 422559f089..0e73bf7fad 100644 --- a/src/library/scala/collection/mutable/FlatHashTable.scala +++ b/src/library/scala/collection/mutable/FlatHashTable.scala @@ -184,7 +184,7 @@ trait FlatHashTable[A] { private def checkConsistent() { for (i <- 0 until table.length) if (table(i) != null && !containsEntry(table(i).asInstanceOf[A])) - assert(false, i+" "+table(i)+" "+table.toString) + assert(false, i+" "+table(i)+" "+table.mkString) } protected def elemHashCode(elem: A) = if (elem == null) 0 else elem.hashCode() diff --git a/src/library/scala/collection/mutable/IndexedSeqView.scala b/src/library/scala/collection/mutable/IndexedSeqView.scala index db1735b543..e864845455 100644 --- a/src/library/scala/collection/mutable/IndexedSeqView.scala +++ b/src/library/scala/collection/mutable/IndexedSeqView.scala @@ -13,6 +13,7 @@ package scala.collection package mutable import generic._ + import TraversableView.NoBuilder /** A non-strict view of a mutable IndexedSeq. @@ -29,7 +30,9 @@ self => def update(idx: Int, elem: A) - trait Transformed[B] extends views.MutableIndexedSeq[B, Coll] with IndexedSeqView[B, Coll] with super.Transformed[B] + trait Transformed[B] extends IndexedSeqView[B, Coll] with super.Transformed[B] { + def update(idx: Int, elem: B) + } trait Sliced extends Transformed[A] with super.Sliced { override def update(idx: Int, elem: A) = diff --git a/src/library/scala/collection/mutable/PriorityQueue.scala b/src/library/scala/collection/mutable/PriorityQueue.scala index 203f1eee15..c4dac9effb 100644 --- a/src/library/scala/collection/mutable/PriorityQueue.scala +++ b/src/library/scala/collection/mutable/PriorityQueue.scala @@ -35,7 +35,7 @@ class PriorityQueue[A](implicit ord: Ordering[A]) { import ord._ - private class ResizableArrayAccess[A] extends ResizableArray[A] { + private final class ResizableArrayAccess[A] extends ResizableArray[A] { @inline def p_size0 = size0 @inline def p_size0_=(s: Int) = size0 = s @inline def p_array = array diff --git a/src/library/scala/collection/views/Transformed.scala b/src/library/scala/collection/views/Transformed.scala deleted file mode 100644 index 189ca127c8..0000000000 --- a/src/library/scala/collection/views/Transformed.scala +++ /dev/null @@ -1,128 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2010, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -// $Id$ - - -package scala.collection -package views - -import generic.CanBuildFrom - -/** These classes act as accumulators for the majority of methods in the - * collections hierarchy. By creating abstract classes rather than using - * the traits exclusively, we avoid creating forwarders in dozens of distinct - * anonymous classes and reduce the size of scala-library.jar by over 200K. - */ -private[collection] trait Transformed -private[collection] abstract class TraversableLike[+B, +Coll] extends TraversableView[B, Coll] with Transformed { - override def foreach[C](f: B => C): Unit -} -private[collection] abstract class IterableLike[+B, +Coll] extends TraversableLike[B, Coll] with IterableView[B, Coll] { - override def iterator: Iterator[B] -} -private[collection] abstract class SeqLike[+B, +Coll] extends IterableLike[B, Coll] with SeqView[B, Coll] { - override def length: Int - override def apply(idx: Int): B -} -private[collection] abstract class IndexedSeqLike[+B, +Coll] extends SeqLike[B, Coll] with IndexedSeqView[B, Coll] { - /** Override to use IndexedSeq's foreach; todo: see whether this is really faster */ - override def foreach[U](f: B => U) = super[IndexedSeqView].foreach(f) -} -private[collection] abstract class MutableIndexedSeq[B, +Coll] extends IndexedSeqLike[B, Coll] { - def update(idx: Int, elem: B) -} - -/** The boilerplate in the following traits factored out of the *ViewLike classes - * to reduce noise. It exists only to specialize the return type of each method. - * It would be unnecessary if scala had virtual classes because the inner classes - * of subtraits would subclass the parent trait inner classes, and the same method - * would then suffice for both. - */ -private[collection] trait TraversableTransformations[+A, +Coll, +This <: TraversableView[A, Coll] with TraversableViewLike[A, Coll, This]] { - self: TraversableViewLike[A, Coll, This] => - - /** Boilerplate methods, to override in each subclass. */ - protected def newAppended[B >: A](that: Traversable[B]): Transformed[B] = new Appended[B] { val rest = that } - protected def newMapped[B](f: A => B): Transformed[B] = new Mapped[B] { val mapping = f } - protected def newFlatMapped[B](f: A => Traversable[B]): Transformed[B] = new FlatMapped[B] { val mapping = f } - protected def newFiltered(p: A => Boolean): Transformed[A] = new Filtered { val pred = p } - protected def newSliced(_from: Int, _until: Int): Transformed[A] = new Sliced { val from = _from; val until = _until } - protected def newDroppedWhile(p: A => Boolean): Transformed[A] = new DroppedWhile { val pred = p } - protected def newTakenWhile(p: A => Boolean): Transformed[A] = new TakenWhile { val pred = p } -} - -private[collection] trait IterableTransformations[+A, +Coll, +This <: IterableView[A, Coll] with IterableViewLike[A, Coll, This]] - extends TraversableTransformations[A, Coll, This] -{ - self: IterableViewLike[A, Coll, This] => - - /** Inherited from TraversableView */ - protected override def newAppended[B >: A](that: Traversable[B]): Transformed[B] = new Appended[B] { val rest = that } - protected override def newMapped[B](f: A => B): Transformed[B] = new Mapped[B] { val mapping = f } - protected override def newFlatMapped[B](f: A => Traversable[B]): Transformed[B] = new FlatMapped[B] { val mapping = f } - protected override def newFiltered(p: A => Boolean): Transformed[A] = new Filtered { val pred = p } - protected override def newSliced(_from: Int, _until: Int): Transformed[A] = new Sliced { val from = _from; val until = _until } - protected override def newDroppedWhile(p: A => Boolean): Transformed[A] = new DroppedWhile { val pred = p } - protected override def newTakenWhile(p: A => Boolean): Transformed[A] = new TakenWhile { val pred = p } - - /** IterableView boilerplate contribution */ - protected def newZipped[B](that: Iterable[B]): Transformed[(A, B)] = new Zipped[B] { - val other = that - } - protected def newZippedAll[A1 >: A, B](that: Iterable[B], _thisElem: A1, _thatElem: B): Transformed[(A1, B)] = new ZippedAll[A1, B] { - val other: Iterable[B] = that - val thisElem = _thisElem - val thatElem = _thatElem - } -} - -private[collection] trait SeqTransformations[+A, +Coll, +This <: SeqView[A, Coll] with SeqViewLike[A, Coll, This]] - extends IterableTransformations[A, Coll, This] -{ - self: SeqViewLike[A, Coll, This] => - - /** Inherited from IterableView */ - protected override def newAppended[B >: A](that: Traversable[B]): Transformed[B] = new Appended[B] { val rest = that } - protected override def newMapped[B](f: A => B): Transformed[B] = new Mapped[B] { val mapping = f } - protected override def newFlatMapped[B](f: A => Traversable[B]): Transformed[B] = new FlatMapped[B] { val mapping = f } - protected override def newFiltered(p: A => Boolean): Transformed[A] = new Filtered { val pred = p } - protected override def newSliced(_from: Int, _until: Int): Transformed[A] = new Sliced { val from = _from; val until = _until } - protected override def newDroppedWhile(p: A => Boolean): Transformed[A] = new DroppedWhile { val pred = p } - protected override def newTakenWhile(p: A => Boolean): Transformed[A] = new TakenWhile { val pred = p } - protected override def newZipped[B](that: Iterable[B]): Transformed[(A, B)] = new Zipped[B] { val other = that } - protected override def newZippedAll[A1 >: A, B](that: Iterable[B], _thisElem: A1, _thatElem: B): Transformed[(A1, B)] = - new ZippedAll[A1, B] { val other = that; val thisElem = _thisElem; val thatElem = _thatElem } - - /** SeqView boilerplate contribution */ - protected def newReversed: Transformed[A] = new Reversed { } - protected def newPatched[B >: A](_from: Int, _patch: Seq[B], _replaced: Int): Transformed[B] = - new Patched[B] { val from = _from; val patch = _patch; val replaced = _replaced } -} - -private[collection] trait IndexedSeqTransformations[+A, +Coll, +This <: IndexedSeqView[A, Coll] with IndexedSeqViewLike[A, Coll, This]] - extends SeqTransformations[A, Coll, This] -{ - self: IndexedSeqViewLike[A, Coll, This] => - - /** Inherited from SeqView */ - protected override def newAppended[B >: A](that: Traversable[B]): Transformed[B] = new Appended[B] { val rest = that } - protected override def newMapped[B](f: A => B): Transformed[B] = new Mapped[B] { val mapping = f } - protected override def newFlatMapped[B](f: A => Traversable[B]): Transformed[B] = new FlatMapped[B] { val mapping = f } - protected override def newFiltered(p: A => Boolean): Transformed[A] = new Filtered { val pred = p } - protected override def newSliced(_from: Int, _until: Int): Transformed[A] = new Sliced { val from = _from; val until = _until } - protected override def newDroppedWhile(p: A => Boolean): Transformed[A] = new DroppedWhile { val pred = p } - protected override def newTakenWhile(p: A => Boolean): Transformed[A] = new TakenWhile { val pred = p } - - protected override def newZipped[B](that: Iterable[B]): Transformed[(A, B)] = new Zipped[B] { val other = that } - protected override def newZippedAll[A1 >: A, B](that: Iterable[B], _thisElem: A1, _thatElem: B): Transformed[(A1, B)] = - new ZippedAll[A1, B] { val other = that; val thisElem = _thisElem; val thatElem = _thatElem } - protected override def newReversed: Transformed[A] = new Reversed { } - protected override def newPatched[B >: A](_from: Int, _patch: Seq[B], _replaced: Int): Transformed[B] = - new Patched[B] { val from = _from; val patch = _patch; val replaced = _replaced } -} diff --git a/src/library/scala/concurrent/MailBox.scala b/src/library/scala/concurrent/MailBox.scala index 3b00d6165d..c23bbf1c80 100644 --- a/src/library/scala/concurrent/MailBox.scala +++ b/src/library/scala/concurrent/MailBox.scala @@ -26,7 +26,7 @@ class MailBox extends AnyRef with ListQueueCreator { def isDefinedAt(msg: Message): Boolean } - private class Receiver[A](receiver: Message =>? A) extends PreReceiver { + private class Receiver[A](receiver: PartialFunction[Message, A]) extends PreReceiver { def isDefinedAt(msg: Message) = receiver.isDefinedAt(msg) @@ -85,7 +85,7 @@ class MailBox extends AnyRef with ListQueueCreator { * Block until there is a message in the mailbox for which the processor * <code>f</code> is defined. */ - def receive[A](f: Message =>? A): A = { + def receive[A](f: PartialFunction[Message, A]): A = { val r = new Receiver(f) scanSentMsgs(r) r.receive() @@ -95,7 +95,7 @@ class MailBox extends AnyRef with ListQueueCreator { * Block until there is a message in the mailbox for which the processor * <code>f</code> is defined or the timeout is over. */ - def receiveWithin[A](msec: Long)(f: Message =>? A): A = { + def receiveWithin[A](msec: Long)(f: PartialFunction[Message, A]): A = { val r = new Receiver(f) scanSentMsgs(r) r.receiveWithin(msec) diff --git a/src/library/scala/io/Source.scala b/src/library/scala/io/Source.scala index e5cf73ff44..e88bfd0bf1 100644 --- a/src/library/scala/io/Source.scala +++ b/src/library/scala/io/Source.scala @@ -313,7 +313,7 @@ abstract class Source extends Iterator[Char] } /** The close() method closes the underlying resource. */ - def close: Unit = + def close(): Unit = if (closeFunction != null) closeFunction() /** The reset() method creates a fresh copy of this Source. */ diff --git a/src/library/scala/math/BigDecimal.scala b/src/library/scala/math/BigDecimal.scala index 2f3c7f131b..6bd6b33484 100644 --- a/src/library/scala/math/BigDecimal.scala +++ b/src/library/scala/math/BigDecimal.scala @@ -100,7 +100,7 @@ object BigDecimal */ def apply(x: Array[Char]): BigDecimal = apply(x, defaultMathContext) def apply(x: Array[Char], mc: MathContext): BigDecimal = - new BigDecimal(new BigDec(x.toString, mc), mc) + new BigDecimal(new BigDec(x.mkString, mc), mc) /** Translates the decimal String representation of a <code>BigDecimal</code> * into a <code>BigDecimal</code>. diff --git a/src/library/scala/package.scala b/src/library/scala/package.scala index bc5b5d36f2..9fa09e3b72 100644 --- a/src/library/scala/package.scala +++ b/src/library/scala/package.scala @@ -64,8 +64,6 @@ package object scala { type Range = scala.collection.immutable.Range val Range = scala.collection.immutable.Range - type =>? [-A, +B] = PartialFunction[A, B] - // Migrated from Predef val $scope = scala.xml.TopScope diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala index ebce675347..ecc81c074e 100644 --- a/src/library/scala/runtime/ScalaRunTime.scala +++ b/src/library/scala/runtime/ScalaRunTime.scala @@ -100,7 +100,7 @@ object ScalaRunTime { if (x == null) throw new UninitializedError else x abstract class Try[+A] { - def Catch[B >: A](handler: Throwable =>? B): B + def Catch[B >: A](handler: PartialFunction[Throwable, B]): B def Finally(fin: => Unit): A } @@ -115,7 +115,7 @@ object ScalaRunTime { def run() { result = block } - def Catch[B >: A](handler: Throwable =>? B): B = + def Catch[B >: A](handler: PartialFunction[Throwable, B]): B = if (exception == null) result else if (handler isDefinedAt exception) handler(exception) else throw exception diff --git a/src/library/scala/util/control/Exception.scala b/src/library/scala/util/control/Exception.scala index 67f9ec183b..356b11df51 100644 --- a/src/library/scala/util/control/Exception.scala +++ b/src/library/scala/util/control/Exception.scala @@ -23,14 +23,14 @@ object Exception // We get lots of crashes using this, so for now we just use Class[_] // type ExClass = Class[_ <: Throwable] - type Catcher[+T] = Throwable =>? T - type ExceptionCatcher[+T] = Exception =>? T + type Catcher[+T] = PartialFunction[Throwable, T] + type ExceptionCatcher[+T] = PartialFunction[Exception, T] // due to the magic of contravariance, Throwable => T is a subtype of // Exception => T, not the other way around. So we manually construct // a Throwable => T and simply rethrow the non-Exceptions. implicit def fromExceptionCatcher[T](pf: ExceptionCatcher[T]): Catcher[T] = { - new (Throwable =>? T) { + new PartialFunction[Throwable, T] { def isDefinedAt(x: Throwable) = x match { case e: Exception if pf.isDefinedAt(e) => true case _ => false @@ -101,7 +101,7 @@ object Exception /** Create a new Catch with the same isDefinedAt logic as this one, * but with the supplied apply method replacing the current one. */ def withApply[U](f: (Throwable) => U): Catch[U] = { - val pf2 = new (Throwable =>? U) { + val pf2 = new PartialFunction[Throwable, U] { def isDefinedAt(x: Throwable) = pf isDefinedAt x def apply(x: Throwable) = f(x) } @@ -139,8 +139,8 @@ object Exception override def toString() = List("Try(<body>)", catcher.toString) mkString " " } - final val nothingCatcher: Throwable =>? Nothing = - new (Throwable =>? Nothing) { + final val nothingCatcher: PartialFunction[Throwable, Nothing] = + new PartialFunction[Throwable, Nothing] { def isDefinedAt(x: Throwable) = false def apply(x: Throwable) = throw x } @@ -207,7 +207,7 @@ object Exception classes exists (_ isAssignableFrom x.getClass) private def pfFromExceptions(exceptions: Class[_]*) = - new (Throwable =>? Nothing) { + new PartialFunction[Throwable, Nothing] { def apply(x: Throwable) = throw x def isDefinedAt(x: Throwable) = wouldMatch(x, exceptions) } diff --git a/src/library/scala/util/parsing/combinator/Parsers.scala b/src/library/scala/util/parsing/combinator/Parsers.scala index 1205d2f911..3aa7cc7de1 100644 --- a/src/library/scala/util/parsing/combinator/Parsers.scala +++ b/src/library/scala/util/parsing/combinator/Parsers.scala @@ -93,7 +93,7 @@ trait Parsers { * `f' applied to the result of this `ParseResult', packaged up as a new `ParseResult'. * If `f' is not defined, `Failure'. */ - def mapPartial[U](f: T =>? U, error: T => String): ParseResult[U] + def mapPartial[U](f: PartialFunction[T, U], error: T => String): ParseResult[U] def flatMapWithNext[U](f: T => Input => ParseResult[U]): ParseResult[U] @@ -119,7 +119,7 @@ trait Parsers { */ case class Success[+T](result: T, override val next: Input) extends ParseResult[T] { def map[U](f: T => U) = Success(f(result), next) - def mapPartial[U](f: T =>? U, error: T => String): ParseResult[U] + def mapPartial[U](f: PartialFunction[T, U], error: T => String): ParseResult[U] = if(f.isDefinedAt(result)) Success(f(result), next) else Failure(error(result), next) @@ -146,7 +146,7 @@ trait Parsers { lastNoSuccess = this def map[U](f: Nothing => U) = this - def mapPartial[U](f: Nothing =>? U, error: Nothing => String): ParseResult[U] = this + def mapPartial[U](f: PartialFunction[Nothing, U], error: Nothing => String): ParseResult[U] = this def flatMapWithNext[U](f: Nothing => Input => ParseResult[U]): ParseResult[U] = this @@ -345,7 +345,7 @@ trait Parsers { * @return a parser that succeeds if the current parser succeeds <i>and</i> `f' is applicable * to the result. If so, the result will be transformed by `f'. */ - def ^? [U](f: T =>? U, error: T => String): Parser[U] = Parser{ in => + def ^? [U](f: PartialFunction[T, U], error: T => String): Parser[U] = Parser{ in => this(in).mapPartial(f, error)}.named(toString+"^?") /** A parser combinator for partial function application @@ -358,7 +358,7 @@ trait Parsers { * @return a parser that succeeds if the current parser succeeds <i>and</i> `f' is applicable * to the result. If so, the result will be transformed by `f'. */ - def ^? [U](f: T =>? U): Parser[U] = ^?(f, r => "Constructor function not defined at "+r) + def ^? [U](f: PartialFunction[T, U]): Parser[U] = ^?(f, r => "Constructor function not defined at "+r) /** A parser combinator that parameterises a subsequent parser with the result of this one @@ -495,7 +495,7 @@ trait Parsers { * @return A parser that succeeds if `f' is applicable to the first element of the input, * applying `f' to it to produce the result. */ - def accept[U](expected: String, f: Elem =>? U): Parser[U] = acceptMatch(expected, f) + def accept[U](expected: String, f: PartialFunction[Elem, U]): Parser[U] = acceptMatch(expected, f) def acceptIf(p: Elem => Boolean)(err: Elem => String): Parser[Elem] = Parser { in => @@ -503,7 +503,7 @@ trait Parsers { else Failure(err(in.first), in) } - def acceptMatch[U](expected: String, f: Elem =>? U): Parser[U] = Parser{ in => + def acceptMatch[U](expected: String, f: PartialFunction[Elem, U]): Parser[U] = Parser{ in => if (f.isDefinedAt(in.first)) Success(f(in.first), in.rest) else Failure(expected+" expected", in) } diff --git a/src/library/scala/xml/Text.scala b/src/library/scala/xml/Text.scala index 84e4cbe78f..3090883bb8 100644 --- a/src/library/scala/xml/Text.scala +++ b/src/library/scala/xml/Text.scala @@ -13,16 +13,22 @@ package scala.xml import collection.mutable.StringBuilder -object Text { - def apply(data: String) = - if (data != null) new Text(data) - else throw new IllegalArgumentException("tried to construct Text with null") - - def unapply(other: Any) = other match { - case x: Text => Some(x.data) - case _ => None - } -} +// XXX This attempt to make Text not a case class revealed a bug in the pattern +// matcher (see ticket #2883) so I've put the case back. (It was/is desirable that +// it not be a case class because it is using the antipattern of passing constructor +// parameters to the superclass where they become vals, but since they will also be +// vals in the subclass, it acquires an underscore to avoid a name clash.) +// +// object Text { +// def apply(data: String) = +// if (data != null) new Text(data) +// else throw new IllegalArgumentException("tried to construct Text with null") +// +// def unapply(other: Any): Option[String] = other match { +// case x: Text => Some(x.data) +// case _ => None +// } +// } /** The class <code>Text</code> implements an XML node for text (PCDATA). * It is used in both non-bound and bound XML representations. @@ -31,9 +37,9 @@ object Text { * * @param text the text contained in this node, may not be null. */ -class Text(data: String) extends Atom[String](data) +case class Text(_data: String) extends Atom[String](_data) { - if (data == null) + if (_data == null) throw new IllegalArgumentException("tried to construct Text with null") /** XXX More hashCode flailing. */ diff --git a/src/library/scala/xml/Utility.scala b/src/library/scala/xml/Utility.scala index 78c0ee9475..1cfe9c79c9 100644 --- a/src/library/scala/xml/Utility.scala +++ b/src/library/scala/xml/Utility.scala @@ -289,9 +289,10 @@ object Utility extends AnyRef with parsing.TokenTests */ def getName(s: String, index: Int): String = { if (index >= s.length) null - else (s drop index) match { - case Seq(x, xs @ _*) if isNameStart(x) => x.toString + (xs takeWhile isNameChar).mkString - case _ => "" + else { + val xs = s drop index + if (xs.nonEmpty && isNameStart(xs.head)) xs takeWhile isNameChar + else "" } } diff --git a/src/library/scala/xml/parsing/FactoryAdapter.scala b/src/library/scala/xml/parsing/FactoryAdapter.scala index 2385f645b5..a83f9677a1 100644 --- a/src/library/scala/xml/parsing/FactoryAdapter.scala +++ b/src/library/scala/xml/parsing/FactoryAdapter.scala @@ -135,7 +135,9 @@ abstract class FactoryAdapter extends DefaultHandler with factory.XMLLoader[Node hStack push null var m: MetaData = Null - var scpe: NamespaceBinding = scopeStack.top + var scpe: NamespaceBinding = + if (scopeStack.isEmpty) TopScope + else scopeStack.top for (i <- 0 until attributes.getLength()) { val qname = attributes getQName i diff --git a/src/library/scala/xml/parsing/MarkupParser.scala b/src/library/scala/xml/parsing/MarkupParser.scala index 2779fe1d7c..a15cd0f7e4 100644 --- a/src/library/scala/xml/parsing/MarkupParser.scala +++ b/src/library/scala/xml/parsing/MarkupParser.scala @@ -32,6 +32,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests self: MarkupParser with MarkupHandler => type PositionType = Int + type InputType = Source def xHandleError(that: Char, msg: String) = reportSyntaxError(msg) @@ -47,6 +48,15 @@ trait MarkupParser extends MarkupParserCommon with TokenTests // var curInput: Source = input + def lookahead(): BufferedIterator[Char] = new BufferedIterator[Char] { + val stream = curInput.toStream + curInput = Source.fromIterable(stream) + val underlying = Source.fromIterable(stream).buffered + + def hasNext = underlying.hasNext + def next = underlying.next + def head = underlying.head + } /** the handler of the markup, returns this */ private val handle: MarkupHandler = this @@ -57,7 +67,6 @@ trait MarkupParser extends MarkupParserCommon with TokenTests /** holds the position in the source file */ var pos: Int = _ - /* used when reading external subset */ var extIndex = -1 @@ -379,20 +388,8 @@ trait MarkupParser extends MarkupParserCommon with TokenTests */ def xCharData: NodeSeq = { xToken("[CDATA[") - val pos1 = pos - val sb: StringBuilder = new StringBuilder() - while (true) { - if (ch==']' && - { sb.append(ch); nextch; ch == ']' } && - { sb.append(ch); nextch; ch == '>' } ) { - sb.setLength(sb.length - 2); - nextch; - return PCData(sb.toString) - } else sb.append( ch ); - nextch; - } - // bq: (todo) increase grace when meeting CDATA section - throw FatalError("this cannot happen"); + def mkResult(pos: Int, s: String): NodeSeq = PCData(s) + xTakeUntil(mkResult, () => pos, "]]>") } /** CharRef ::= "&#" '0'..'9' {'0'..'9'} ";" diff --git a/src/library/scala/xml/parsing/MarkupParserCommon.scala b/src/library/scala/xml/parsing/MarkupParserCommon.scala index c4ba2ccf15..57c46c4685 100644 --- a/src/library/scala/xml/parsing/MarkupParserCommon.scala +++ b/src/library/scala/xml/parsing/MarkupParserCommon.scala @@ -18,9 +18,16 @@ import Utility.Escapes.{ pairs => unescape } * All members should be accessed through those. */ private[scala] trait MarkupParserCommon extends TokenTests { - // type InputType // Source, CharArrayReader + private final val SU: Char = 0x1A + protected def unreachable = Predef.error("Cannot be reached.") + // type HandleType // MarkupHandler, SymbolicXMLBuilder - // type PositionType // Int, Position + + type InputType // Source, CharArrayReader + type PositionType // Int, Position + + /** Create a lookahead reader which does not influence the input */ + def lookahead(): BufferedIterator[Char] def ch: Char def nextch: Char @@ -48,4 +55,41 @@ private[scala] trait MarkupParserCommon extends TokenTests { // def returning[T](x: T)(f: T => Unit): T = { f(x) ; x } + + /** Take characters from input stream until given String "until" + * is seen. Once seen, the accumulated characters are passed + * along with the current Position to the supplied handler function. + */ + protected def xTakeUntil[T]( + handler: (PositionType, String) => T, + positioner: () => PositionType, + until: String): T = + { + val sb = new StringBuilder + val head = until charAt 0 + val rest = until drop 1 + + while (true) { + if (ch == head && peek(rest)) + return handler(positioner(), sb.toString) + else if (ch == SU) + xHandleError(ch, "") // throws TruncatedXML in compiler + + sb append ch + nextch + } + unreachable + } + + /** Create a non-destructive lookahead reader and see if the head + * of the input would match the given String. If yes, return true + * and drop the entire String from input; if no, return false + * and leave input unchanged. + */ + private def peek(lookingFor: String): Boolean = + (lookahead() take lookingFor.length sameElements lookingFor.iterator) && { + // drop the chars from the real reader (all lookahead + orig) + (0 to lookingFor.length) foreach (_ => nextch) + true + } } diff --git a/src/scalap/scala/tools/scalap/Main.scala b/src/scalap/scala/tools/scalap/Main.scala index 59c77813dd..59c46df25f 100644 --- a/src/scalap/scala/tools/scalap/Main.scala +++ b/src/scalap/scala/tools/scalap/Main.scala @@ -284,8 +284,8 @@ object Main { * The short name of the package (without prefix) */ def name: String = "" - def classes: List[ClassRep[AbstractFile]] = Nil - def packages: List[ClassPath[AbstractFile]] = Nil - def sourcepaths: List[AbstractFile] = Nil + val classes: List[ClassRep[AbstractFile]] = Nil + val packages: List[ClassPath[AbstractFile]] = Nil + val sourcepaths: List[AbstractFile] = Nil } } diff --git a/src/scalap/scala/tools/scalap/scalax/rules/Rule.scala b/src/scalap/scala/tools/scalap/scalax/rules/Rule.scala index f65c688aa7..1500b81050 100644 --- a/src/scalap/scala/tools/scalap/scalax/rules/Rule.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/Rule.scala @@ -56,9 +56,9 @@ trait Rule[-In, +Out, +A, +X] extends (In => Result[Out, A, X]) { def ^^[B](fa2b : A => B) = map(fa2b) - def ^^?[B](pf : A =>? B) = filter (pf.isDefinedAt(_)) ^^ pf + def ^^?[B](pf : PartialFunction[A, B]) = filter (pf.isDefinedAt(_)) ^^ pf - def ??(pf : A =>? Any) = filter (pf.isDefinedAt(_)) + def ??(pf : PartialFunction[A, Any]) = filter (pf.isDefinedAt(_)) def -^[B](b : B) = map { any => b } @@ -73,7 +73,7 @@ trait Rule[-In, +Out, +A, +X] extends (In => Result[Out, A, X]) { def >->[Out2, B, X2 >: X](fa2resultb : A => Result[Out2, B, X2]) = flatMap { a => any => fa2resultb(a) } - def >>?[Out2, B, X2 >: X](pf : A =>? Rule[Out, Out2, B, X2]) = filter(pf isDefinedAt _) flatMap pf + def >>?[Out2, B, X2 >: X](pf : PartialFunction[A, Rule[Out, Out2, B, X2]]) = filter(pf isDefinedAt _) flatMap pf def >>&[B, X2 >: X](fa2ruleb : A => Out => Result[Any, B, X2]) = flatMap { a => out => fa2ruleb(a)(out) mapOut { any => out } } diff --git a/src/swing/scala/swing/Reactions.scala b/src/swing/scala/swing/Reactions.scala index a2327d7b18..14d4deb981 100644 --- a/src/swing/scala/swing/Reactions.scala +++ b/src/swing/scala/swing/Reactions.scala @@ -27,7 +27,7 @@ object Reactions { } } - type Reaction = Event =>? Unit + type Reaction = PartialFunction[Event, Unit] /** * A Reaction implementing this trait is strongly referenced in the reaction list diff --git a/test/files/neg/t2421b.check b/test/files/neg/t2421b.check new file mode 100644 index 0000000000..f666a7d9d7 --- /dev/null +++ b/test/files/neg/t2421b.check @@ -0,0 +1,4 @@ +t2421b.scala:12: error: could not find implicit value for parameter aa: Test.F[Test.A] + f + ^ +one error found
\ No newline at end of file diff --git a/test/files/neg/t2421b.scala b/test/files/neg/t2421b.scala new file mode 100644 index 0000000000..d8159a8c37 --- /dev/null +++ b/test/files/neg/t2421b.scala @@ -0,0 +1,17 @@ +object Test { + class A + class B + class C + class F[X] + + def f(implicit aa: F[A]) = println(aa) + + // implicit def a : F[A] = new F[A]() + implicit def b[X <: B] = new F[X]() + + f +} + +/* bug: +error: type arguments [Test2.A] do not conform to method b's type parameter bounds [X <: Test2.B] +*/
\ No newline at end of file diff --git a/test/files/neg/t2641.check b/test/files/neg/t2641.check index 07900d0796..771624e8d9 100644 --- a/test/files/neg/t2641.check +++ b/test/files/neg/t2641.check @@ -25,7 +25,7 @@ t2641.scala:27: error: illegal inheritance; superclass Any trait Sliced extends Transformed[A] with super.Sliced { ^ t2641.scala:27: error: illegal inheritance; superclass Any - is not a subclass of the superclass TraversableLike + is not a subclass of the superclass Object of the mixin trait Sliced trait Sliced extends Transformed[A] with super.Sliced { ^ diff --git a/test/files/neg/t2870.check b/test/files/neg/t2870.check new file mode 100644 index 0000000000..6577577d3f --- /dev/null +++ b/test/files/neg/t2870.check @@ -0,0 +1,7 @@ +t2870.scala:1: error: not found: type Jar +class Jars(jar: Jar) + ^ +t2870.scala:6: error: illegal cyclic reference involving value <import> + val scala = fromClasspathString(javaClassPath) + ^ +two errors found diff --git a/test/files/neg/t2870.scala b/test/files/neg/t2870.scala new file mode 100755 index 0000000000..4de19242e3 --- /dev/null +++ b/test/files/neg/t2870.scala @@ -0,0 +1,9 @@ +class Jars(jar: Jar) + +object Jars { + import scala.util.Properties.javaClassPath + + val scala = fromClasspathString(javaClassPath) + + def fromClasspathString(s: String): Jars = null +} diff --git a/test/files/pos/t2421b.scala b/test/files/pos/t2421b.scala new file mode 100644 index 0000000000..0df3461662 --- /dev/null +++ b/test/files/pos/t2421b.scala @@ -0,0 +1,19 @@ +object Test { + class A + class B + class C + class F[X] + + def f(implicit aa: F[A]) = println(aa) + + implicit def a : F[A] = new F[A]() + implicit def b[X <: B] = new F[X]() + + f +} +/* bug: +error: ambiguous implicit values: + both method b in object Test1 of type [X <: Test1.B]Test1.F[X] + and method a in object Test1 of type => Test1.F[Test1.A] + match expected type Test1.F[Test1.A] +*/ diff --git a/test/files/pos/t2810.scala b/test/files/pos/t2810.scala new file mode 100644 index 0000000000..c85eca164a --- /dev/null +++ b/test/files/pos/t2810.scala @@ -0,0 +1,8 @@ + + + + +object Test { + val closeable1: { def close(): Unit } = new scala.io.Source { val iter: Iterator[Char] = "".iterator } + val closeable2: { def close(): Unit } = new java.io.Closeable { def close() = {} } +} diff --git a/test/files/pos/t2867.scala b/test/files/pos/t2867.scala new file mode 100644 index 0000000000..0434a380b9 --- /dev/null +++ b/test/files/pos/t2867.scala @@ -0,0 +1 @@ +case class A(l: List[_]*) diff --git a/test/files/positions/Scaladoc6.scala b/test/files/positions/Scaladoc6.scala new file mode 100644 index 0000000000..8beda625ae --- /dev/null +++ b/test/files/positions/Scaladoc6.scala @@ -0,0 +1,10 @@ +object Scaladoc6 { + { + /** + * Foo + */ + val i = 23 + } + + def f {} +} diff --git a/test/files/positions/Scaladoc7.scala b/test/files/positions/Scaladoc7.scala new file mode 100644 index 0000000000..6175222e3f --- /dev/null +++ b/test/files/positions/Scaladoc7.scala @@ -0,0 +1,6 @@ +object Scaladoc7 { + /** + * Foo + */ + val Pair(i, j) = (1, 2) +} diff --git a/test/files/positions/Scaladoc8.scala b/test/files/positions/Scaladoc8.scala new file mode 100644 index 0000000000..519d6ca06c --- /dev/null +++ b/test/files/positions/Scaladoc8.scala @@ -0,0 +1,6 @@ +/** + * Foo + */ +object Scaladoc8 { + +} diff --git a/test/files/run/bug2354.scala b/test/files/run/bug2354.scala new file mode 100644 index 0000000000..f46db13a95 --- /dev/null +++ b/test/files/run/bug2354.scala @@ -0,0 +1,17 @@ +import scala.xml.parsing._ +import scala.io.Source + +object Test +{ + val xml_good = "<title><![CDATA[Hello [tag]]]></title>" + val xml_bad = "<title><![CDATA[Hello [tag] ]]></title>" + + val parser1 = ConstructingParser.fromSource(Source.fromString(xml_good),false) + val parser2 = ConstructingParser.fromSource(Source.fromString(xml_bad),false) + + def main(args: Array[String]): Unit = { + parser1.document + parser2.document + } +} + diff --git a/test/files/run/bug2876.scala b/test/files/run/bug2876.scala new file mode 100644 index 0000000000..f71879ebff --- /dev/null +++ b/test/files/run/bug2876.scala @@ -0,0 +1,7 @@ +object Test +{ + def main(args: Array[String]): Unit = { + "x".view.filter(_ => true).take(1) + } +} + diff --git a/test/files/run/map_java_conversions.scala b/test/files/run/map_java_conversions.scala new file mode 100644 index 0000000000..4f9f8a915a --- /dev/null +++ b/test/files/run/map_java_conversions.scala @@ -0,0 +1,60 @@ + + + + + +object Test { + + def main(args: Array[String]) { + import collection.JavaConversions._ + + test(new java.util.HashMap[String, String]) + test(new java.util.Properties) + testConcMap + } + + def testConcMap { + import collection.JavaConversions._ + + val concMap = new java.util.concurrent.ConcurrentHashMap[String, String] + + test(concMap) + val cmap = asConcurrentMap(concMap) + cmap.putIfAbsent("absentKey", "absentValue") + cmap.put("somekey", "somevalue") + assert(cmap.remove("somekey", "somevalue") == true) + assert(cmap.replace("absentKey", "newAbsentValue") == Some("absentValue")) + assert(cmap.replace("absentKey", "newAbsentValue", ".......") == true) + } + + def test(m: collection.mutable.Map[String, String]) { + m.clear + assert(m.size == 0) + + m.put("key", "value") + assert(m.size == 1) + + assert(m.put("key", "anotherValue") == Some("value")) + assert(m.put("key2", "value2") == None) + assert(m.size == 2) + + m += (("key3", "value3")) + assert(m.size == 3) + + m -= "key2" + assert(m.size == 2) + assert(m.nonEmpty) + assert(m.remove("key") == Some("anotherValue")) + + m.clear + for (i <- 0 until 10) m += (("key" + i, "value" + i)) + for ((k, v) <- m) assert(k.startsWith("key")) + } + +} + + + + + + diff --git a/test/files/run/t2849.scala b/test/files/run/t2849.scala new file mode 100644 index 0000000000..68094de736 --- /dev/null +++ b/test/files/run/t2849.scala @@ -0,0 +1,46 @@ + + + +import scala.collection.immutable.SortedSet +import scala.collection.immutable.TreeSet + + + +object Test { + + def main(args: Array[String]) { + ticketExample + similarExample + } + + def ticketExample { + var big = 100000 + + var aSortedSet: SortedSet[Int] = TreeSet(big) + + for (i <- 1 until 10000) { + aSortedSet = (aSortedSet - big) ++ (TreeSet(i, big - 1)) + big = big - 1 + if (i % 1000 == 0) { + aSortedSet.until(i) + } + } + } + + def similarExample { + var big = 100 + + var aSortedSet: SortedSet[Int] = TreeSet(big) + + for (i <- 1 until 10000) { + aSortedSet = (aSortedSet - big) ++ (TreeSet(i, big - 1)) + big + big = big - 1 + if (i % 1000 == 0) { + aSortedSet.until(i) + } + } + } + +} + + diff --git a/test/pending/run/bug2364.check b/test/pending/run/bug2364.check new file mode 100644 index 0000000000..219305e43a --- /dev/null +++ b/test/pending/run/bug2364.check @@ -0,0 +1 @@ +<test></test> diff --git a/test/pending/run/bug2364.scala b/test/pending/run/bug2364.scala new file mode 100644 index 0000000000..d5805a13b8 --- /dev/null +++ b/test/pending/run/bug2364.scala @@ -0,0 +1,60 @@ +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream +import com.sun.xml.internal.fastinfoset._ +import com.sun.xml.internal.fastinfoset.sax._ +import scala.xml.parsing.NoBindingFactoryAdapter +import scala.xml._ + +// Note - this is in pending because com.sun.xml.etc is not standard, +// and I don't have time to extract a smaller test. + +object Test { + def main(args: Array[String]) { + val node = <test/> + val bytes = new ByteArrayOutputStream + val serializer = new SAXDocumentSerializer() + + serializer.setOutputStream(bytes) + serializer.startDocument() + serialize(node, serializer) + serializer.endDocument() + println(parse(new ByteArrayInputStream(bytes.toByteArray))) + } + def serialize(node: Node, serializer: SAXDocumentSerializer) { + node match { + case _ : ProcInstr | _ : Comment | _ : EntityRef => + case x : Atom[_] => + val chars = x.text.toCharArray + serializer.characters(chars, 0, chars.length) + case _ : Elem => + serializer.startElement("", node.label.toLowerCase, node.label.toLowerCase, attributes(node.attributes)) + for (m <- node.child) serialize(m, serializer) + serializer.endElement("", node.label.toLowerCase, node.label.toLowerCase) + } + } + def parse(str: ByteArrayInputStream) = { + val parser = new SAXDocumentParser + val fac = new NoBindingFactoryAdapter + + parser.setContentHandler(fac) + try { + parser.parse(str) + } catch { + case x: Exception => + x.printStackTrace + } + fac.rootElem + } + def attributes(d: MetaData) = { + val attrs = new AttributesHolder + + if (d != null) { + for (attr <- d) { + val sb = new StringBuilder() + Utility.sequenceToXML(attr.value, TopScope, sb, true) + attrs.addAttribute(new QualifiedName("", "", attr.key.toLowerCase), sb.toString) + } + } + attrs + } +} |