summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/actors/scala/actors/Actor.scala490
-rw-r--r--src/actors/scala/actors/ActorCanReply.scala2
-rw-r--r--src/actors/scala/actors/ActorTask.scala9
-rw-r--r--src/actors/scala/actors/Channel.scala2
-rw-r--r--src/actors/scala/actors/Combinators.scala2
-rw-r--r--src/actors/scala/actors/Future.scala4
-rw-r--r--src/actors/scala/actors/InternalActor.scala509
-rw-r--r--src/actors/scala/actors/InternalReplyReactor.scala161
-rw-r--r--src/actors/scala/actors/OutputChannel.scala2
-rw-r--r--src/actors/scala/actors/ReactChannel.scala2
-rw-r--r--src/actors/scala/actors/Reactor.scala6
-rw-r--r--src/actors/scala/actors/ReactorCanReply.scala2
-rw-r--r--src/actors/scala/actors/ReplyReactor.scala165
-rw-r--r--src/actors/scala/actors/ReplyReactorTask.scala4
-rw-r--r--src/actors/scala/actors/UncaughtException.scala2
-rw-r--r--src/build/maven/continuations-plugin-pom.xml9
-rw-r--r--src/build/maven/jline-pom.xml9
-rw-r--r--src/build/maven/maven-deploy.xml23
-rw-r--r--src/build/maven/scala-actors-pom.xml61
-rw-r--r--src/build/maven/scala-compiler-pom.xml9
-rw-r--r--src/build/maven/scala-dbc-pom.xml9
-rw-r--r--src/build/maven/scala-dotnet-library-pom.xml9
-rw-r--r--src/build/maven/scala-library-pom.xml9
-rw-r--r--src/build/maven/scala-partest-pom.xml9
-rw-r--r--src/build/maven/scala-swing-pom.xml9
-rw-r--r--src/build/maven/scalap-pom.xml9
-rw-r--r--src/build/pack.xml122
-rw-r--r--src/compiler/scala/reflect/internal/Definitions.scala144
-rw-r--r--src/compiler/scala/reflect/internal/Flags.scala4
-rw-r--r--src/compiler/scala/reflect/internal/Importers.scala2
-rw-r--r--src/compiler/scala/reflect/internal/Kinds.scala23
-rw-r--r--src/compiler/scala/reflect/internal/StdNames.scala5
-rw-r--r--src/compiler/scala/reflect/internal/SymbolTable.scala6
-rw-r--r--src/compiler/scala/reflect/internal/Symbols.scala124
-rw-r--r--src/compiler/scala/reflect/internal/TreeInfo.scala20
-rw-r--r--src/compiler/scala/reflect/internal/TreePrinters.scala2
-rw-r--r--src/compiler/scala/reflect/internal/Trees.scala5
-rw-r--r--src/compiler/scala/reflect/internal/Types.scala179
-rw-r--r--src/compiler/scala/reflect/internal/settings/MutableSettings.scala1
-rw-r--r--src/compiler/scala/reflect/runtime/Settings.scala3
-rw-r--r--src/compiler/scala/reflect/runtime/ToolBoxes.scala4
-rw-r--r--src/compiler/scala/reflect/runtime/Universe.scala5
-rw-r--r--src/compiler/scala/tools/ant/ScalaBazaar.scala316
-rw-r--r--src/compiler/scala/tools/ant/ScalaTool.scala3
-rw-r--r--src/compiler/scala/tools/ant/antlib.xml6
-rw-r--r--src/compiler/scala/tools/cmd/FromString.scala12
-rwxr-xr-xsrc/compiler/scala/tools/nsc/ast/DocComments.scala59
-rw-r--r--src/compiler/scala/tools/nsc/ast/NodePrinters.scala565
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala147
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeDSL.scala5
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala8
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala8
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala65
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala14
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala60
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala58
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/Inliners.scala2
-rw-r--r--src/compiler/scala/tools/nsc/doc/DocFactory.scala18
-rw-r--r--src/compiler/scala/tools/nsc/doc/Settings.scala2
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala2
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala12
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/SyntaxHigh.scala12
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/page/Template.scala29
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/resource/lib/template.css24
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala7
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala60
-rw-r--r--src/compiler/scala/tools/nsc/interactive/RangePositions.scala2
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala4
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala12
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Naming.scala20
-rw-r--r--src/compiler/scala/tools/nsc/matching/ParallelMatching.scala6
-rw-r--r--src/compiler/scala/tools/nsc/matching/Patterns.scala3
-rw-r--r--src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala4
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala76
-rw-r--r--src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Positions.scala9
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala18
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala11
-rw-r--r--src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala24
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala184
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala286
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala151
-rw-r--r--src/compiler/scala/tools/nsc/transform/TailCalls.scala131
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala201
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala29
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Duplicators.scala28
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala12
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala66
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala9
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala432
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala26
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala50
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala400
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Unapplies.scala5
-rw-r--r--src/compiler/scala/tools/nsc/util/Position.scala13
-rw-r--r--src/compiler/scala/tools/util/color/CString.scala19
-rw-r--r--src/compiler/scala/tools/util/color/package.scala1
-rw-r--r--src/library/scala/Function.scala7
-rw-r--r--src/library/scala/PartialFunction.scala134
-rw-r--r--src/library/scala/Specializable.scala12
-rw-r--r--src/library/scala/collection/GenIterableLike.scala64
-rw-r--r--src/library/scala/collection/GenMapLike.scala2
-rw-r--r--src/library/scala/collection/GenSeqLike.scala157
-rw-r--r--src/library/scala/collection/GenTraversableLike.scala112
-rw-r--r--src/library/scala/collection/GenTraversableOnce.scala65
-rw-r--r--src/library/scala/collection/IterableLike.scala1
-rw-r--r--src/library/scala/collection/Iterator.scala14
-rw-r--r--src/library/scala/collection/JavaConversions.scala947
-rwxr-xr-xsrc/library/scala/collection/JavaConverters.scala492
-rw-r--r--src/library/scala/collection/MapLike.scala14
-rw-r--r--src/library/scala/collection/SeqLike.scala49
-rw-r--r--src/library/scala/collection/TraversableLike.scala76
-rw-r--r--src/library/scala/collection/concurrent/TrieMap.scala2
-rw-r--r--src/library/scala/collection/convert/DecorateAsJava.scala316
-rw-r--r--src/library/scala/collection/convert/DecorateAsScala.scala208
-rw-r--r--src/library/scala/collection/convert/Decorators.scala46
-rw-r--r--src/library/scala/collection/convert/WrapAsJava.scala285
-rw-r--r--src/library/scala/collection/convert/WrapAsScala.scala212
-rw-r--r--src/library/scala/collection/convert/Wrappers.scala469
-rw-r--r--src/library/scala/collection/convert/package.scala18
-rw-r--r--src/library/scala/collection/generic/GenericTraversableTemplate.scala25
-rw-r--r--src/library/scala/collection/immutable/List.scala18
-rw-r--r--src/library/scala/collection/immutable/StringLike.scala15
-rw-r--r--src/library/scala/collection/mutable/FlatArray.scala11
-rw-r--r--src/library/scala/collection/mutable/Stack.scala2
-rw-r--r--src/library/scala/collection/mutable/WeakHashMap.scala5
-rw-r--r--src/library/scala/collection/parallel/ParIterableLike.scala3
-rw-r--r--src/library/scala/collection/parallel/ParSeqLike.scala16
-rw-r--r--src/library/scala/collection/parallel/immutable/ParHashMap.scala4
-rw-r--r--src/library/scala/collection/parallel/immutable/ParHashSet.scala2
-rw-r--r--src/library/scala/collection/parallel/immutable/ParRange.scala2
-rw-r--r--src/library/scala/collection/parallel/immutable/ParVector.scala2
-rw-r--r--src/library/scala/collection/parallel/mutable/ParArray.scala6
-rw-r--r--src/library/scala/collection/parallel/mutable/ParHashMap.scala2
-rw-r--r--src/library/scala/collection/parallel/mutable/ParHashSet.scala2
-rw-r--r--src/library/scala/collection/parallel/mutable/ParTrieMap.scala2
-rw-r--r--src/library/scala/concurrent/Awaitable.scala11
-rw-r--r--src/library/scala/concurrent/ConcurrentPackageObject.scala21
-rw-r--r--src/library/scala/concurrent/DelayedLazyVal.scala3
-rw-r--r--src/library/scala/concurrent/ExecutionContext.scala93
-rw-r--r--src/library/scala/concurrent/Future.scala131
-rw-r--r--src/library/scala/concurrent/Promise.scala16
-rw-r--r--src/library/scala/concurrent/Scheduler.scala2
-rw-r--r--src/library/scala/concurrent/default/SchedulerImpl.scala.disabled2
-rw-r--r--src/library/scala/concurrent/default/TaskImpl.scala.disabled2
-rw-r--r--src/library/scala/concurrent/impl/ExecutionContextImpl.scala87
-rw-r--r--src/library/scala/concurrent/impl/Future.scala74
-rw-r--r--src/library/scala/concurrent/impl/Promise.scala31
-rw-r--r--src/library/scala/concurrent/package.scala31
-rw-r--r--src/library/scala/concurrent/util/Duration.scala578
-rw-r--r--src/library/scala/reflect/api/Positions.scala18
-rw-r--r--src/library/scala/reflect/api/TreePrinters.scala2
-rw-r--r--src/library/scala/reflect/api/Trees.scala45
-rw-r--r--src/library/scala/runtime/AbstractPartialFunction.scala84
-rw-r--r--src/library/scala/testing/Show.scala2
-rw-r--r--src/library/scala/util/Duration.scala485
-rw-r--r--src/library/scala/util/Timeout.scala33
-rw-r--r--src/library/scala/util/control/Exception.scala5
-rw-r--r--src/library/scala/util/matching/Regex.scala58
-rwxr-xr-xsrc/library/scala/xml/Elem.scala8
-rwxr-xr-xsrc/library/scala/xml/XML.scala17
-rw-r--r--src/library/scala/xml/factory/LoggedNodeFactory.scala2
-rwxr-xr-xsrc/library/scala/xml/parsing/MarkupParser.scala22
-rw-r--r--src/manual/scala/man1/fsc.scala5
-rw-r--r--src/manual/scala/man1/sbaz.scala209
-rw-r--r--src/manual/scala/man1/scala.scala1
-rw-r--r--src/manual/scala/man1/scalac.scala5
-rw-r--r--src/manual/scala/man1/scaladoc.scala1
-rw-r--r--src/manual/scala/man1/scalap.scala1
-rw-r--r--src/manual/scala/tools/docutil/resources/index.html17
-rw-r--r--src/partest/scala/tools/partest/PartestTask.scala11
-rw-r--r--src/partest/scala/tools/partest/ScaladocModelTest.scala124
-rw-r--r--src/partest/scala/tools/partest/nest/AntRunner.scala1
-rw-r--r--src/partest/scala/tools/partest/nest/ConsoleFileManager.scala9
-rw-r--r--src/partest/scala/tools/partest/nest/DirectRunner.scala9
-rw-r--r--src/partest/scala/tools/partest/nest/FileManager.scala1
-rw-r--r--src/partest/scala/tools/partest/nest/ReflectiveRunner.scala4
-rw-r--r--src/partest/scala/tools/partest/nest/SBTRunner.scala4
-rw-r--r--src/partest/scala/tools/partest/nest/Worker.scala1
184 files changed, 6470 insertions, 5534 deletions
diff --git a/src/actors/scala/actors/Actor.scala b/src/actors/scala/actors/Actor.scala
index b746f68268..bc9bbc6ef0 100644
--- a/src/actors/scala/actors/Actor.scala
+++ b/src/actors/scala/actors/Actor.scala
@@ -1,3 +1,5 @@
+
+
/* __ *\
** ________ ___ / / ___ Scala API **
** / __/ __// _ | / / / _ | (c) 2005-2011, LAMP/EPFL **
@@ -46,7 +48,7 @@ object Actor extends Combinators {
Terminated = Value
}
- private[actors] val tl = new ThreadLocal[ReplyReactor]
+ private[actors] val tl = new ThreadLocal[InternalReplyReactor]
// timer thread runs as daemon
private[actors] val timer = new Timer(true)
@@ -59,15 +61,15 @@ object Actor extends Combinators {
*
* @return returns the currently executing actor.
*/
- def self: Actor = self(Scheduler)
+ def self: Actor = self(Scheduler).asInstanceOf[Actor]
- private[actors] def self(sched: IScheduler): Actor =
- rawSelf(sched).asInstanceOf[Actor]
+ private[actors] def self(sched: IScheduler): InternalActor =
+ rawSelf(sched).asInstanceOf[InternalActor]
- private[actors] def rawSelf: ReplyReactor =
+ private[actors] def rawSelf: InternalReplyReactor =
rawSelf(Scheduler)
- private[actors] def rawSelf(sched: IScheduler): ReplyReactor = {
+ private[actors] def rawSelf(sched: IScheduler): InternalReplyReactor = {
val s = tl.get
if (s eq null) {
val r = new ActorProxy(Thread.currentThread, sched)
@@ -245,9 +247,9 @@ object Actor extends Combinators {
def eventloop(f: PartialFunction[Any, Unit]): Nothing =
rawSelf.react(new RecursiveProxyHandler(rawSelf, f))
- private class RecursiveProxyHandler(a: ReplyReactor, f: PartialFunction[Any, Unit])
- extends scala.runtime.AbstractPartialFunction[Any, Unit] {
- def _isDefinedAt(m: Any): Boolean =
+ private class RecursiveProxyHandler(a: InternalReplyReactor, 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) {
if (f.isDefinedAt(m)) f(m)
@@ -259,7 +261,7 @@ object Actor extends Combinators {
* Returns the actor which sent the last received message.
*/
def sender: OutputChannel[Any] =
- rawSelf.sender
+ rawSelf.internalSender
/**
* Sends `msg` to the actor waiting in a call to `!?`.
@@ -302,7 +304,7 @@ object Actor extends Combinators {
def andThen[b](other: => b): Unit
}
- implicit def mkBody[a](body: => a) = new Body[a] {
+ implicit def mkBody[a](body: => a) = new InternalActor.Body[a] {
def andThen[b](other: => b): Unit = rawSelf.seq(body, other)
}
@@ -397,476 +399,12 @@ object Actor extends Combinators {
* @define channel actor's mailbox
*/
@SerialVersionUID(-781154067877019505L)
-trait Actor extends AbstractActor with ReplyReactor with ActorCanReply with InputChannel[Any] with Serializable {
-
- /* The following two fields are only used when the actor
- * suspends by blocking its underlying thread, for example,
- * when waiting in a receive or synchronous send.
- */
- @volatile
- private var isSuspended = false
-
- /* This field is used to communicate the received message from
- * the invocation of send to the place where the thread of
- * the receiving actor resumes inside receive/receiveWithin.
- */
- @volatile
- private var received: Option[Any] = None
-
- protected[actors] override def scheduler: IScheduler = Scheduler
-
- private[actors] override def startSearch(msg: Any, replyTo: OutputChannel[Any], handler: PartialFunction[Any, Any]) =
- if (isSuspended) {
- () => synchronized {
- mailbox.append(msg, replyTo)
- resumeActor()
- }
- } else super.startSearch(msg, replyTo, handler)
-
- // we override this method to check `shouldExit` before suspending
- private[actors] override def searchMailbox(startMbox: MQueue[Any],
- 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)
- handler.isDefinedAt(msg)
- })
- if (tmpMbox ne mailbox)
- tmpMbox.foreach((m, s) => mailbox.append(m, s))
- if (null eq qel) {
- synchronized {
- // in mean time new stuff might have arrived
- if (!sendBuffer.isEmpty) {
- tmpMbox = new MQueue[Any]("Temp")
- drainSendBuffer(tmpMbox)
- // keep going
- } else {
- // very important to check for `shouldExit` at this point
- // since linked actors might have set it after we checked
- // last time (e.g., at the beginning of `react`)
- if (shouldExit) exit()
- waitingFor = handler
- // see Reactor.searchMailbox
- throw Actor.suspendException
- }
- }
- } else {
- resumeReceiver((qel.msg, qel.session), handler, resumeOnSameThread)
- done = true
- }
- }
- }
-
- private[actors] override def makeReaction(fun: () => Unit, handler: PartialFunction[Any, Any], msg: Any): Runnable =
- new ActorTask(this, fun, handler, msg)
-
- /** See the companion object's `receive` method. */
- def receive[R](f: PartialFunction[Any, R]): R = {
- assert(Actor.self(scheduler) == this, "receive from channel belonging to other actor")
-
- synchronized {
- if (shouldExit) exit() // links
- drainSendBuffer(mailbox)
- }
-
- var done = false
- while (!done) {
- val qel = mailbox.extractFirst((m: Any, replyTo: OutputChannel[Any]) => {
- senders = replyTo :: senders
- val matches = f.isDefinedAt(m)
- senders = senders.tail
- matches
- })
- if (null eq qel) {
- synchronized {
- // in mean time new stuff might have arrived
- if (!sendBuffer.isEmpty) {
- drainSendBuffer(mailbox)
- // keep going
- } else {
- waitingFor = f
- isSuspended = true
- scheduler.managedBlock(blocker)
- drainSendBuffer(mailbox)
- // keep going
- }
- }
- } else {
- received = Some(qel.msg)
- senders = qel.session :: senders
- done = true
- }
- }
-
- val result = f(received.get)
- received = None
- senders = senders.tail
- result
- }
-
- /** See the companion object's `receiveWithin` method. */
- def receiveWithin[R](msec: Long)(f: PartialFunction[Any, R]): R = {
- assert(Actor.self(scheduler) == this, "receive from channel belonging to other actor")
-
- synchronized {
- if (shouldExit) exit() // links
- drainSendBuffer(mailbox)
- }
-
- // first, remove spurious TIMEOUT message from mailbox if any
- mailbox.extractFirst((m: Any, replyTo: OutputChannel[Any]) => m == TIMEOUT)
-
- val receiveTimeout = () => {
- if (f.isDefinedAt(TIMEOUT)) {
- received = Some(TIMEOUT)
- senders = this :: senders
- } else
- sys.error("unhandled timeout")
- }
-
- var done = false
- while (!done) {
- val qel = mailbox.extractFirst((m: Any, replyTo: OutputChannel[Any]) => {
- senders = replyTo :: senders
- val matches = f.isDefinedAt(m)
- senders = senders.tail
- matches
- })
- if (null eq qel) {
- val todo = synchronized {
- // in mean time new stuff might have arrived
- if (!sendBuffer.isEmpty) {
- drainSendBuffer(mailbox)
- // keep going
- () => {}
- } else if (msec == 0L) {
- done = true
- receiveTimeout
- } else {
- if (onTimeout.isEmpty) {
- if (!f.isDefinedAt(TIMEOUT))
- sys.error("unhandled timeout")
-
- val thisActor = this
- onTimeout = Some(new TimerTask {
- def run() {
- thisActor.send(TIMEOUT, thisActor)
- }
- })
- Actor.timer.schedule(onTimeout.get, msec)
- }
-
- // It is possible that !onTimeout.isEmpty, but TIMEOUT is not yet in mailbox
- // See SI-4759
- waitingFor = f
- received = None
- isSuspended = true
- scheduler.managedBlock(blocker)
- drainSendBuffer(mailbox)
- // keep going
- () => {}
- }
- }
- todo()
- } else {
- synchronized {
- if (!onTimeout.isEmpty) {
- onTimeout.get.cancel()
- onTimeout = None
- }
- }
- received = Some(qel.msg)
- senders = qel.session :: senders
- done = true
- }
- }
-
- val result = f(received.get)
- received = None
- senders = senders.tail
- result
- }
-
- /** See the companion object's `react` method. */
- override def react(handler: PartialFunction[Any, Unit]): Nothing = {
- synchronized {
- if (shouldExit) exit()
- }
- super.react(handler)
- }
-
- /** See the companion object's `reactWithin` method. */
- override def reactWithin(msec: Long)(handler: PartialFunction[Any, Unit]): Nothing = {
- synchronized {
- if (shouldExit) exit()
- }
- super.reactWithin(msec)(handler)
- }
-
- /** Receives the next message from the mailbox */
- def ? : Any = receive {
- case x => x
- }
-
- // guarded by lock of this
- // never throws SuspendActorControl
- 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 ActorTask(this, null, f, msg)
- scheduler executeFromActor task
- }
-
- /* Used for notifying scheduler when blocking inside receive/receiveWithin. */
- private object blocker extends scala.concurrent.ManagedBlocker {
- def block() = {
- Actor.this.suspendActor()
- true
- }
- def isReleasable =
- !Actor.this.isSuspended
- }
-
- private def suspendActor() = synchronized {
- while (isSuspended) {
- try {
- wait()
- } catch {
- case _: InterruptedException =>
- }
- }
- // links: check if we should exit
- if (shouldExit) exit()
- }
-
- private def resumeActor() {
- isSuspended = false
- notify()
- }
-
- private[actors] override def exiting = synchronized {
- _state == Actor.State.Terminated
- }
-
- // guarded by this
- private[actors] override def dostart() {
- // Reset various flags.
- //
- // Note that we do *not* reset `trapExit`. The reason is that
- // users should be able to set the field in the constructor
- // and before `act` is called.
- exitReason = 'normal
- shouldExit = false
-
- super.dostart()
- }
+trait Actor extends InternalActor with ReplyReactor {
override def start(): Actor = synchronized {
super.start()
this
}
- /** State of this actor */
- override def getState: Actor.State.Value = synchronized {
- if (isSuspended) {
- if (onTimeout.isEmpty)
- Actor.State.Blocked
- else
- Actor.State.TimedBlocked
- } else
- super.getState
- }
-
- // guarded by this
- private[actors] var links: List[AbstractActor] = Nil
-
- /**
- * Links `self` to actor `to`.
- *
- * @param to the actor to link to
- * @return the parameter actor
- */
- def link(to: AbstractActor): AbstractActor = {
- assert(Actor.self(scheduler) == this, "link called on actor different from self")
- this linkTo to
- to linkTo this
- to
}
- /**
- * Links `self` to the actor defined by `body`.
- *
- * @param body the body of the actor to link to
- * @return the parameter actor
- */
- def link(body: => Unit): Actor = {
- assert(Actor.self(scheduler) == this, "link called on actor different from self")
- val a = new Actor {
- def act() = body
- override final val scheduler: IScheduler = Actor.this.scheduler
- }
- link(a)
- a.start()
- a
- }
-
- private[actors] def linkTo(to: AbstractActor) = synchronized {
- links = to :: links
- }
-
- /**
- * Unlinks `self` from actor `from`.
- */
- def unlink(from: AbstractActor) {
- assert(Actor.self(scheduler) == this, "unlink called on actor different from self")
- this unlinkFrom from
- from unlinkFrom this
- }
-
- private[actors] def unlinkFrom(from: AbstractActor) = synchronized {
- links = links.filterNot(from.==)
- }
-
- @volatile
- var trapExit = false
- // guarded by this
- private var exitReason: AnyRef = 'normal
- // guarded by this
- private[actors] var shouldExit = false
-
- /**
- * Terminates execution of `self` with the following effect on
- * linked actors:
- *
- * For each linked actor `a` with `trapExit` set to `'''true'''`,
- * send message `Exit(self, reason)` to `a`.
- *
- * For each linked actor `a` with `trapExit` set to `'''false'''`
- * (default), call `a.exit(reason)` if `reason != 'normal`.
- */
- protected[actors] def exit(reason: AnyRef): Nothing = {
- synchronized {
- exitReason = reason
- }
- exit()
- }
-
- /**
- * Terminates with exit reason `'normal`.
- */
- protected[actors] override def exit(): Nothing = {
- val todo = synchronized {
- if (!links.isEmpty)
- exitLinked()
- else
- () => {}
- }
- todo()
- super.exit()
- }
-
- // Assume !links.isEmpty
- // guarded by this
- private[actors] def exitLinked(): () => Unit = {
- _state = Actor.State.Terminated
- // reset waitingFor, otherwise getState returns Suspended
- waitingFor = Reactor.waitingForNone
- // remove this from links
- val mylinks = links.filterNot(this.==)
- // unlink actors
- mylinks.foreach(unlinkFrom(_))
- // return closure that locks linked actors
- () => {
- mylinks.foreach((linked: AbstractActor) => {
- linked.synchronized {
- if (!linked.exiting) {
- linked.unlinkFrom(this)
- linked.exit(this, exitReason)
- }
- }
- })
- }
- }
-
- // Assume !links.isEmpty
- // guarded by this
- private[actors] def exitLinked(reason: AnyRef): () => Unit = {
- exitReason = reason
- exitLinked()
- }
-
- // Assume !this.exiting
- private[actors] def exit(from: AbstractActor, reason: AnyRef) {
- if (trapExit) {
- this ! Exit(from, reason)
- }
- else if (reason != 'normal)
- synchronized {
- shouldExit = true
- exitReason = reason
- // resume this Actor in a way that
- // causes it to exit
- // (because shouldExit == true)
- if (isSuspended)
- resumeActor()
- else if (waitingFor ne Reactor.waitingForNone) {
- waitingFor = Reactor.waitingForNone
- // it doesn't matter what partial function we are passing here
- scheduleActor(waitingFor, null)
- /* Here we should not throw a SuspendActorControl,
- since the current method is called from an actor that
- is in the process of exiting.
-
- Therefore, the contract for scheduleActor is that
- it never throws a SuspendActorControl.
- */
- }
- }
- }
-
- /** Requires qualified private, because `RemoteActor` must
- * register a termination handler.
- */
- private[actors] def onTerminate(f: => Unit) {
- scheduler.onTerminate(this) { f }
- }
-}
-
-
-/**
- * Used as the timeout pattern in
- * <a href="Actor.html#receiveWithin(Long)" target="contentFrame">
- * <code>receiveWithin</code></a> and
- * <a href="Actor.html#reactWithin(Long)" target="contentFrame">
- * <code>reactWithin</code></a>.
- *
- * @example {{{
- * receiveWithin(500) {
- * case (x, y) => ...
- * case TIMEOUT => ...
- * }
- * }}}
- *
- * @author Philipp Haller
- */
-case object TIMEOUT
-
-
-/** Sent to an actor with `trapExit` set to `'''true'''` whenever one of its
- * linked actors terminates.
- *
- * @param from the actor that terminated
- * @param reason the reason that caused the actor to terminate
- */
-case class Exit(from: AbstractActor, reason: AnyRef)
-
-/** Manages control flow of actor executions.
- *
- * @author Philipp Haller
- */
-private[actors] class SuspendActorControl extends ControlThrowable
diff --git a/src/actors/scala/actors/ActorCanReply.scala b/src/actors/scala/actors/ActorCanReply.scala
index b307aafa57..d92fb183c0 100644
--- a/src/actors/scala/actors/ActorCanReply.scala
+++ b/src/actors/scala/actors/ActorCanReply.scala
@@ -18,7 +18,7 @@ import scala.concurrent.SyncVar
* @author Philipp Haller
*/
private[actors] trait ActorCanReply extends ReactorCanReply {
- this: AbstractActor with ReplyReactor =>
+ this: AbstractActor with InternalReplyReactor =>
override def !?(msg: Any): Any = {
val replyCh = new Channel[Any](Actor.self(scheduler))
diff --git a/src/actors/scala/actors/ActorTask.scala b/src/actors/scala/actors/ActorTask.scala
index 090d0448f0..bb04302238 100644
--- a/src/actors/scala/actors/ActorTask.scala
+++ b/src/actors/scala/actors/ActorTask.scala
@@ -17,7 +17,7 @@ package scala.actors
* changes to the underlying var invisible.) I can't figure out what's supposed
* to happen, so I renamed the constructor parameter to at least be less confusing.
*/
-private[actors] class ActorTask(actor: Actor,
+private[actors] class ActorTask(actor: InternalActor,
fun: () => Unit,
handler: PartialFunction[Any, Any],
initialMsg: Any)
@@ -32,7 +32,7 @@ private[actors] class ActorTask(actor: Actor,
}
protected override def terminateExecution(e: Throwable) {
- val senderInfo = try { Some(actor.sender) } catch {
+ val senderInfo = try { Some(actor.internalSender) } catch {
case _: Exception => None
}
// !!! If this is supposed to be setting the current contents of the
@@ -45,13 +45,16 @@ private[actors] class ActorTask(actor: Actor,
e)
val todo = actor.synchronized {
- if (!actor.links.isEmpty)
+ val res = if (!actor.links.isEmpty)
actor.exitLinked(uncaught)
else {
super.terminateExecution(e)
() => {}
}
+ actor.internalPostStop
+ res
}
+
todo()
}
diff --git a/src/actors/scala/actors/Channel.scala b/src/actors/scala/actors/Channel.scala
index 62331239e8..36cee66b42 100644
--- a/src/actors/scala/actors/Channel.scala
+++ b/src/actors/scala/actors/Channel.scala
@@ -34,7 +34,7 @@ case class ! [a](ch: Channel[a], msg: a)
* @define actor channel
* @define channel channel
*/
-class Channel[Msg](val receiver: Actor) extends InputChannel[Msg] with OutputChannel[Msg] with CanReply[Msg, Any] {
+class Channel[Msg](val receiver: InternalActor) extends InputChannel[Msg] with OutputChannel[Msg] with CanReply[Msg, Any] {
type Future[+P] = scala.actors.Future[P]
diff --git a/src/actors/scala/actors/Combinators.scala b/src/actors/scala/actors/Combinators.scala
index 5276c7843e..c1a9095614 100644
--- a/src/actors/scala/actors/Combinators.scala
+++ b/src/actors/scala/actors/Combinators.scala
@@ -16,7 +16,7 @@ private[actors] trait Combinators {
* Enables the composition of suspendable closures using `andThen`,
* `loop`, `loopWhile`, etc.
*/
- implicit def mkBody[a](body: => a): Actor.Body[a]
+ implicit def mkBody[a](body: => a): InternalActor.Body[a]
/**
* Repeatedly executes `body`.
diff --git a/src/actors/scala/actors/Future.scala b/src/actors/scala/actors/Future.scala
index eec43013d3..735c13190b 100644
--- a/src/actors/scala/actors/Future.scala
+++ b/src/actors/scala/actors/Future.scala
@@ -200,8 +200,8 @@ object Futures {
Actor.timer.schedule(timerTask, timeout)
def awaitWith(partFuns: Seq[PartialFunction[Any, Pair[Int, Any]]]) {
- val reaction: PartialFunction[Any, Unit] = new scala.runtime.AbstractPartialFunction[Any, Unit] {
- def _isDefinedAt(msg: Any) = msg match {
+ 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/InternalActor.scala b/src/actors/scala/actors/InternalActor.scala
new file mode 100644
index 0000000000..c94da5b9fd
--- /dev/null
+++ b/src/actors/scala/actors/InternalActor.scala
@@ -0,0 +1,509 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2005-2011, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+package scala.actors
+import java.util.TimerTask
+import scala.util.control.ControlThrowable
+
+private[actors] object InternalActor {
+ private[actors] trait Body[a] {
+ def andThen[b](other: => b): Unit
+ }
+}
+
+private[actors] trait InternalActor extends AbstractActor with InternalReplyReactor with ActorCanReply with InputChannel[Any] with Serializable {
+
+ /* The following two fields are only used when the actor
+ * suspends by blocking its underlying thread, for example,
+ * when waiting in a receive or synchronous send.
+ */
+ @volatile
+ private[actors] var isSuspended = false
+
+ /* This field is used to communicate the received message from
+ * the invocation of send to the place where the thread of
+ * the receiving actor resumes inside receive/receiveWithin.
+ */
+ @volatile
+ private var received: Option[Any] = None
+
+ protected[actors] override def scheduler: IScheduler = Scheduler
+
+ private[actors] override def startSearch(msg: Any, replyTo: OutputChannel[Any], handler: PartialFunction[Any, Any]) =
+ if (isSuspended) {
+ () =>
+ synchronized {
+ mailbox.append(msg, replyTo)
+ resumeActor()
+ }
+ } else super.startSearch(msg, replyTo, handler)
+
+ // we override this method to check `shouldExit` before suspending
+ private[actors] override def searchMailbox(startMbox: MQueue[Any],
+ 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)
+ handler.isDefinedAt(msg)
+ })
+ if (tmpMbox ne mailbox)
+ tmpMbox.foreach((m, s) => mailbox.append(m, s))
+ if (null eq qel) {
+ synchronized {
+ // in mean time new stuff might have arrived
+ if (!sendBuffer.isEmpty) {
+ tmpMbox = new MQueue[Any]("Temp")
+ drainSendBuffer(tmpMbox)
+ // keep going
+ } else {
+ // very important to check for `shouldExit` at this point
+ // since linked actors might have set it after we checked
+ // last time (e.g., at the beginning of `react`)
+ if (shouldExit) exit()
+ waitingFor = handler
+ // see Reactor.searchMailbox
+ throw Actor.suspendException
+ }
+ }
+ } else {
+ resumeReceiver((qel.msg, qel.session), handler, resumeOnSameThread)
+ done = true
+ }
+ }
+ }
+
+ private[actors] override def makeReaction(fun: () => Unit, handler: PartialFunction[Any, Any], msg: Any): Runnable =
+ new ActorTask(this, fun, handler, msg)
+
+ /** See the companion object's `receive` method. */
+ def receive[R](f: PartialFunction[Any, R]): R = {
+ assert(Actor.self(scheduler) == this, "receive from channel belonging to other actor")
+
+ synchronized {
+ if (shouldExit) exit() // links
+ drainSendBuffer(mailbox)
+ }
+
+ var done = false
+ while (!done) {
+ val qel = mailbox.extractFirst((m: Any, replyTo: OutputChannel[Any]) => {
+ senders = replyTo :: senders
+ val matches = f.isDefinedAt(m)
+ senders = senders.tail
+ matches
+ })
+ if (null eq qel) {
+ synchronized {
+ // in mean time new stuff might have arrived
+ if (!sendBuffer.isEmpty) {
+ drainSendBuffer(mailbox)
+ // keep going
+ } else {
+ waitingFor = f
+ isSuspended = true
+ scheduler.managedBlock(blocker)
+ drainSendBuffer(mailbox)
+ // keep going
+ }
+ }
+ } else {
+ received = Some(qel.msg)
+ senders = qel.session :: senders
+ done = true
+ }
+ }
+
+ val result = f(received.get)
+ received = None
+ senders = senders.tail
+ result
+ }
+
+ /** See the companion object's `receiveWithin` method. */
+ def receiveWithin[R](msec: Long)(f: PartialFunction[Any, R]): R = {
+ assert(Actor.self(scheduler) == this, "receive from channel belonging to other actor")
+
+ synchronized {
+ if (shouldExit) exit() // links
+ drainSendBuffer(mailbox)
+ }
+
+ // first, remove spurious TIMEOUT message from mailbox if any
+ mailbox.extractFirst((m: Any, replyTo: OutputChannel[Any]) => m == TIMEOUT)
+
+ val receiveTimeout = () => {
+ if (f.isDefinedAt(TIMEOUT)) {
+ received = Some(TIMEOUT)
+ senders = this :: senders
+ } else
+ sys.error("unhandled timeout")
+ }
+
+ var done = false
+ while (!done) {
+ val qel = mailbox.extractFirst((m: Any, replyTo: OutputChannel[Any]) => {
+ senders = replyTo :: senders
+ val matches = f.isDefinedAt(m)
+ senders = senders.tail
+ matches
+ })
+ if (null eq qel) {
+ val todo = synchronized {
+ // in mean time new stuff might have arrived
+ if (!sendBuffer.isEmpty) {
+ drainSendBuffer(mailbox)
+ // keep going
+ () => {}
+ } else if (msec == 0L) {
+ done = true
+ receiveTimeout
+ } else {
+ if (onTimeout.isEmpty) {
+ if (!f.isDefinedAt(TIMEOUT))
+ sys.error("unhandled timeout")
+
+ val thisActor = this
+ onTimeout = Some(new TimerTask {
+ def run() {
+ thisActor.send(TIMEOUT, thisActor)
+ }
+ })
+ Actor.timer.schedule(onTimeout.get, msec)
+ }
+
+ // It is possible that !onTimeout.isEmpty, but TIMEOUT is not yet in mailbox
+ // See SI-4759
+ waitingFor = f
+ received = None
+ isSuspended = true
+ scheduler.managedBlock(blocker)
+ drainSendBuffer(mailbox)
+ // keep going
+ () => {}
+ }
+ }
+ todo()
+ } else {
+ synchronized {
+ if (!onTimeout.isEmpty) {
+ onTimeout.get.cancel()
+ onTimeout = None
+ }
+ }
+ received = Some(qel.msg)
+ senders = qel.session :: senders
+ done = true
+ }
+ }
+
+ val result = f(received.get)
+ received = None
+ senders = senders.tail
+ result
+ }
+
+ /** See the companion object's `react` method. */
+ override def react(handler: PartialFunction[Any, Unit]): Nothing = {
+ synchronized {
+ if (shouldExit) exit()
+ }
+ super.react(handler)
+ }
+
+ /** See the companion object's `reactWithin` method. */
+ override def reactWithin(msec: Long)(handler: PartialFunction[Any, Unit]): Nothing = {
+ synchronized {
+ if (shouldExit) exit()
+ }
+ super.reactWithin(msec)(handler)
+ }
+
+ /** Receives the next message from the mailbox */
+ def ? : Any = receive {
+ case x => x
+ }
+
+ // guarded by lock of this
+ // never throws SuspendActorControl
+ 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 ActorTask(this, null, f, msg)
+ scheduler executeFromActor task
+ }
+
+ /* Used for notifying scheduler when blocking inside receive/receiveWithin. */
+ private object blocker extends scala.concurrent.ManagedBlocker {
+ def block() = {
+ InternalActor.this.suspendActor()
+ true
+ }
+ def isReleasable =
+ !InternalActor.this.isSuspended
+ }
+
+ private def suspendActor() = synchronized {
+ while (isSuspended) {
+ try {
+ wait()
+ } catch {
+ case _: InterruptedException =>
+ }
+ }
+ // links: check if we should exit
+ if (shouldExit) exit()
+ }
+
+ private def resumeActor() {
+ isSuspended = false
+ notify()
+ }
+
+ private[actors] override def exiting = synchronized {
+ _state == Actor.State.Terminated
+ }
+
+ // guarded by this
+ private[actors] override def dostart() {
+ // Reset various flags.
+ //
+ // Note that we do *not* reset `trapExit`. The reason is that
+ // users should be able to set the field in the constructor
+ // and before `act` is called.
+ exitReason = 'normal
+ shouldExit = false
+
+ super.dostart()
+ }
+
+ override def start(): InternalActor = synchronized {
+ super.start()
+ this
+ }
+
+ /** State of this actor */
+ override def getState: Actor.State.Value = synchronized {
+ if (isSuspended) {
+ if (onTimeout.isEmpty)
+ Actor.State.Blocked
+ else
+ Actor.State.TimedBlocked
+ } else
+ super.getState
+ }
+
+ // guarded by this
+ private[actors] var links: List[AbstractActor] = Nil
+
+ /**
+ * Links <code>self</code> to actor <code>to</code>.
+ *
+ * @param to the actor to link to
+ * @return the parameter actor
+ */
+ def link(to: AbstractActor): AbstractActor = {
+ assert(Actor.self(scheduler) == this, "link called on actor different from self")
+ this linkTo to
+ to linkTo this
+ to
+ }
+
+ /**
+ * Links <code>self</code> to the actor defined by <code>body</code>.
+ *
+ * @param body the body of the actor to link to
+ * @return the parameter actor
+ */
+ def link(body: => Unit): Actor = {
+ assert(Actor.self(scheduler) == this, "link called on actor different from self")
+ val a = new Actor {
+ def act() = body
+ override final val scheduler: IScheduler = InternalActor.this.scheduler
+ }
+ link(a)
+ a.start()
+ a
+ }
+
+ private[actors] def linkTo(to: AbstractActor) = synchronized {
+ links = to :: links
+ }
+
+ /**
+ * Unlinks <code>self</code> from actor <code>from</code>.
+ */
+ def unlink(from: AbstractActor) {
+ assert(Actor.self(scheduler) == this, "unlink called on actor different from self")
+ this unlinkFrom from
+ from unlinkFrom this
+ }
+
+ private[actors] def unlinkFrom(from: AbstractActor) = synchronized {
+ links = links.filterNot(from.==)
+ }
+
+ @volatile
+ private[actors] var _trapExit = false
+
+ def trapExit = _trapExit
+
+ def trapExit_=(value: Boolean) = _trapExit = value
+
+ // guarded by this
+ private var exitReason: AnyRef = 'normal
+ // guarded by this
+ private[actors] var shouldExit = false
+
+ /**
+ * <p>
+ * Terminates execution of <code>self</code> with the following
+ * effect on linked actors:
+ * </p>
+ * <p>
+ * For each linked actor <code>a</code> with
+ * <code>trapExit</code> set to <code>true</code>, send message
+ * <code>Exit(self, reason)</code> to <code>a</code>.
+ * </p>
+ * <p>
+ * For each linked actor <code>a</code> with
+ * <code>trapExit</code> set to <code>false</code> (default),
+ * call <code>a.exit(reason)</code> if
+ * <code>reason != 'normal</code>.
+ * </p>
+ */
+ protected[actors] def exit(reason: AnyRef): Nothing = {
+ synchronized {
+ exitReason = reason
+ }
+ exit()
+ }
+
+ /**
+ * Terminates with exit reason <code>'normal</code>.
+ */
+ protected[actors] override def exit(): Nothing = {
+ val todo = synchronized {
+ if (!links.isEmpty)
+ exitLinked()
+ else
+ () => {}
+ }
+ todo()
+ super.exit()
+ }
+
+ // Assume !links.isEmpty
+ // guarded by this
+ private[actors] def exitLinked(): () => Unit = {
+ _state = Actor.State.Terminated
+ // reset waitingFor, otherwise getState returns Suspended
+ waitingFor = Reactor.waitingForNone
+ // remove this from links
+ val mylinks = links.filterNot(this.==)
+ // unlink actors
+ mylinks.foreach(unlinkFrom(_))
+ // return closure that locks linked actors
+ () => {
+ mylinks.foreach((linked: AbstractActor) => {
+ linked.synchronized {
+ if (!linked.exiting) {
+ linked.unlinkFrom(this)
+ linked.exit(this, exitReason)
+ }
+ }
+ })
+ }
+ }
+
+ // Assume !links.isEmpty
+ // guarded by this
+ private[actors] def exitLinked(reason: AnyRef): () => Unit = {
+ exitReason = reason
+ exitLinked()
+ }
+
+ // Assume !this.exiting
+ private[actors] def exit(from: AbstractActor, reason: AnyRef) {
+ if (trapExit) {
+ this ! Exit(from, reason)
+ } else if (reason != 'normal)
+ stop(reason)
+ }
+
+ /* Requires qualified private, because <code>RemoteActor</code> must
+ * register a termination handler.
+ */
+ private[actors] def onTerminate(f: => Unit) {
+ scheduler.onTerminate(this) { f }
+ }
+
+ private[actors] def internalPostStop() = {}
+
+ private[actors] def stop(reason: AnyRef): Unit = {
+ synchronized {
+ shouldExit = true
+ exitReason = reason
+ // resume this Actor in a way that
+ // causes it to exit
+ // (because shouldExit == true)
+ if (isSuspended)
+ resumeActor()
+ else if (waitingFor ne Reactor.waitingForNone) {
+ waitingFor = Reactor.waitingForNone
+ // it doesn't matter what partial function we are passing here
+ val task = new ActorTask(this, null, waitingFor, null)
+ scheduler execute task
+ /* Here we should not throw a SuspendActorControl,
+ since the current method is called from an actor that
+ is in the process of exiting.
+
+ Therefore, the contract for scheduleActor is that
+ it never throws a SuspendActorControl.
+ */
+ }
+ }
+ }
+}
+
+/**
+ * Used as the timeout pattern in
+ * <a href="Actor.html#receiveWithin(Long)" target="contentFrame">
+ * <code>receiveWithin</code></a> and
+ * <a href="Actor.html#reactWithin(Long)" target="contentFrame">
+ * <code>reactWithin</code></a>.
+ *
+ * @example {{{
+ * receiveWithin(500) {
+ * case (x, y) => ...
+ * case TIMEOUT => ...
+ * }
+ * }}}
+ *
+ * @author Philipp Haller
+ */
+case object TIMEOUT
+
+/**
+ * Sent to an actor
+ * with `trapExit` set to `true` whenever one of its linked actors
+ * terminates.
+ *
+ * @param from the actor that terminated
+ * @param reason the reason that caused the actor to terminate
+ */
+case class Exit(from: AbstractActor, reason: AnyRef)
+
+/**
+ * Manages control flow of actor executions.
+ *
+ * @author Philipp Haller
+ */
+private[actors] class SuspendActorControl extends ControlThrowable
diff --git a/src/actors/scala/actors/InternalReplyReactor.scala b/src/actors/scala/actors/InternalReplyReactor.scala
new file mode 100644
index 0000000000..38295138d4
--- /dev/null
+++ b/src/actors/scala/actors/InternalReplyReactor.scala
@@ -0,0 +1,161 @@
+package scala.actors
+
+import java.util.{TimerTask}
+
+/**
+ * Extends the [[scala.actors.Reactor]]
+ * trait with methods to reply to the sender of a message.
+ * Sending a message to a <code>ReplyReactor</code> implicitly
+ * passes a reference to the sender together with the message.
+ *
+ * @author Philipp Haller
+ *
+ * @define actor `ReplyReactor`
+ */
+trait InternalReplyReactor extends Reactor[Any] with ReactorCanReply {
+
+ /* A list of the current senders. The head of the list is
+ * the sender of the message that was received last.
+ */
+ @volatile
+ private[actors] var senders: List[OutputChannel[Any]] = List()
+
+ /* This option holds a TimerTask when the actor waits in a
+ * reactWithin. The TimerTask is cancelled when the actor
+ * resumes.
+ *
+ * guarded by this
+ */
+ private[actors] var onTimeout: Option[TimerTask] = None
+
+ /**
+ * Returns the $actor which sent the last received message.
+ */
+ protected[actors] def internalSender: OutputChannel[Any] = senders.head
+
+ /**
+ * Replies with <code>msg</code> to the sender.
+ */
+ protected[actors] def reply(msg: Any) {
+ internalSender ! msg
+ }
+
+ override def !(msg: Any) {
+ send(msg, Actor.rawSelf(scheduler))
+ }
+
+ override def forward(msg: Any) {
+ send(msg, Actor.sender)
+ }
+
+ private[actors] override def resumeReceiver(item: (Any, OutputChannel[Any]), handler: PartialFunction[Any, Any], onSameThread: Boolean) {
+ synchronized {
+ if (!onTimeout.isEmpty) {
+ onTimeout.get.cancel()
+ onTimeout = None
+ }
+ }
+ senders = List(item._2)
+ super.resumeReceiver(item, handler, onSameThread)
+ }
+
+ private[actors] override def searchMailbox(startMbox: MQueue[Any],
+ 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)
+ handler.isDefinedAt(msg)
+ })
+ if (tmpMbox ne mailbox)
+ tmpMbox.foreach((m, s) => mailbox.append(m, s))
+ if (null eq qel) {
+ synchronized {
+ // in mean time new stuff might have arrived
+ if (!sendBuffer.isEmpty) {
+ tmpMbox = new MQueue[Any]("Temp")
+ drainSendBuffer(tmpMbox)
+ // keep going
+ } else {
+ waitingFor = handler
+ // see Reactor.searchMailbox
+ throw Actor.suspendException
+ }
+ }
+ } else {
+ resumeReceiver((qel.msg, qel.session), handler, resumeOnSameThread)
+ done = true
+ }
+ }
+ }
+
+ private[actors] override def makeReaction(fun: () => Unit, handler: PartialFunction[Any, Any], msg: Any): Runnable =
+ new ReplyReactorTask(this, fun, handler, msg)
+
+ protected[actors] override def react(handler: PartialFunction[Any, Unit]): Nothing = {
+ assert(Actor.rawSelf(scheduler) == this, "react on channel belonging to other actor")
+ super.react(handler)
+ }
+
+
+ /**
+ * Receives a message from this $actor's mailbox within a certain
+ * time span.
+ *
+ * This method never returns. Therefore, the rest of the computation
+ * has to be contained in the actions of the partial function.
+ *
+ * @param msec the time span before timeout
+ * @param handler a partial function with message patterns and actions
+ */
+ protected[actors] def reactWithin(msec: Long)(handler: PartialFunction[Any, Unit]): Nothing = {
+ assert(Actor.rawSelf(scheduler) == this, "react on channel belonging to other actor")
+
+ synchronized { drainSendBuffer(mailbox) }
+
+ // first, remove spurious TIMEOUT message from mailbox if any
+ mailbox.extractFirst((m: Any, replyTo: OutputChannel[Any]) => m == TIMEOUT)
+
+ while (true) {
+ val qel = mailbox.extractFirst((m: Any, replyTo: OutputChannel[Any]) => {
+ senders = List(replyTo)
+ handler isDefinedAt m
+ })
+ if (null eq qel) {
+ synchronized {
+ // in mean time new messages might have arrived
+ if (!sendBuffer.isEmpty) {
+ drainSendBuffer(mailbox)
+ // keep going
+ } else if (msec == 0L) {
+ // throws Actor.suspendException
+ resumeReceiver((TIMEOUT, this), handler, false)
+ } else {
+ waitingFor = handler
+ val thisActor = this
+ onTimeout = Some(new TimerTask {
+ def run() { thisActor.send(TIMEOUT, thisActor) }
+ })
+ Actor.timer.schedule(onTimeout.get, msec)
+ throw Actor.suspendException
+ }
+ }
+ } else
+ resumeReceiver((qel.msg, qel.session), handler, false)
+ }
+ throw Actor.suspendException
+ }
+
+ override def getState: Actor.State.Value = synchronized {
+ if (waitingFor ne Reactor.waitingForNone) {
+ if (onTimeout.isEmpty)
+ Actor.State.Suspended
+ else
+ Actor.State.TimedSuspended
+ } else
+ _state
+ }
+
+}
diff --git a/src/actors/scala/actors/OutputChannel.scala b/src/actors/scala/actors/OutputChannel.scala
index 089b3d0981..1fba684975 100644
--- a/src/actors/scala/actors/OutputChannel.scala
+++ b/src/actors/scala/actors/OutputChannel.scala
@@ -43,5 +43,5 @@ trait OutputChannel[-Msg] {
/**
* Returns the `Actor` that is receiving from this $actor.
*/
- def receiver: Actor
+ def receiver: InternalActor
}
diff --git a/src/actors/scala/actors/ReactChannel.scala b/src/actors/scala/actors/ReactChannel.scala
index fccde34272..81a166c1a4 100644
--- a/src/actors/scala/actors/ReactChannel.scala
+++ b/src/actors/scala/actors/ReactChannel.scala
@@ -12,7 +12,7 @@ package scala.actors
/**
* @author Philipp Haller
*/
-private[actors] class ReactChannel[Msg](receiver: ReplyReactor) extends InputChannel[Msg] {
+private[actors] class ReactChannel[Msg](receiver: InternalReplyReactor) extends InputChannel[Msg] {
private case class SendToReactor(channel: ReactChannel[Msg], msg: Msg)
diff --git a/src/actors/scala/actors/Reactor.scala b/src/actors/scala/actors/Reactor.scala
index 7d21e9f91e..206a97d97c 100644
--- a/src/actors/scala/actors/Reactor.scala
+++ b/src/actors/scala/actors/Reactor.scala
@@ -38,8 +38,8 @@ private[actors] object Reactor {
}
}
- val waitingForNone: PartialFunction[Any, Unit] = new scala.runtime.AbstractPartialFunction[Any, Unit] {
- def _isDefinedAt(x: Any) = false
+ val waitingForNone: PartialFunction[Any, Unit] = new PartialFunction[Any, Unit] {
+ def isDefinedAt(x: Any) = false
def apply(x: Any) {}
}
}
@@ -253,7 +253,7 @@ trait Reactor[Msg >: Null] extends OutputChannel[Msg] with Combinators {
_state
}
- implicit def mkBody[A](body: => A) = new Actor.Body[A] {
+ implicit def mkBody[A](body: => A) = new InternalActor.Body[A] {
def andThen[B](other: => B): Unit = Reactor.this.seq(body, other)
}
diff --git a/src/actors/scala/actors/ReactorCanReply.scala b/src/actors/scala/actors/ReactorCanReply.scala
index 68f9999776..dabd0832f0 100644
--- a/src/actors/scala/actors/ReactorCanReply.scala
+++ b/src/actors/scala/actors/ReactorCanReply.scala
@@ -16,7 +16,7 @@ package scala.actors
* @author Philipp Haller
*/
private[actors] trait ReactorCanReply extends CanReply[Any, Any] {
- _: ReplyReactor =>
+ _: InternalReplyReactor =>
type Future[+P] = scala.actors.Future[P]
diff --git a/src/actors/scala/actors/ReplyReactor.scala b/src/actors/scala/actors/ReplyReactor.scala
index 0e5ce00c91..0ffbbd3cce 100644
--- a/src/actors/scala/actors/ReplyReactor.scala
+++ b/src/actors/scala/actors/ReplyReactor.scala
@@ -5,165 +5,12 @@
** /____/\___/_/ |_/____/_/ | | **
** |/ **
\* */
-
package scala.actors
-import java.util.{Timer, TimerTask}
-
-/**
- * Extends the [[scala.actors.Reactor]] trait with methods to reply to the
- * sender of a message.
- *
- * Sending a message to a `ReplyReactor` implicitly passes a reference to
- * the sender together with the message.
- *
- * @author Philipp Haller
- *
- * @define actor `ReplyReactor`
- */
-trait ReplyReactor extends Reactor[Any] with ReactorCanReply {
-
- /* A list of the current senders. The head of the list is
- * the sender of the message that was received last.
- */
- @volatile
- private[actors] var senders: List[OutputChannel[Any]] = List()
-
- /* This option holds a TimerTask when the actor waits in a
- * reactWithin. The TimerTask is cancelled when the actor
- * resumes.
- *
- * guarded by this
- */
- private[actors] var onTimeout: Option[TimerTask] = None
-
- /**
- * Returns the $actor which sent the last received message.
- */
- protected[actors] def sender: OutputChannel[Any] = senders.head
-
- /**
- * Replies with `msg` to the sender.
- */
- protected[actors] def reply(msg: Any) {
- sender ! msg
- }
-
- override def !(msg: Any) {
- send(msg, Actor.rawSelf(scheduler))
- }
-
- override def forward(msg: Any) {
- send(msg, Actor.sender)
- }
-
- private[actors] override def resumeReceiver(item: (Any, OutputChannel[Any]), handler: PartialFunction[Any, Any], onSameThread: Boolean) {
- synchronized {
- if (!onTimeout.isEmpty) {
- onTimeout.get.cancel()
- onTimeout = None
- }
- }
- senders = List(item._2)
- super.resumeReceiver(item, handler, onSameThread)
- }
-
- private[actors] override def searchMailbox(startMbox: MQueue[Any],
- 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)
- handler.isDefinedAt(msg)
- })
- if (tmpMbox ne mailbox)
- tmpMbox.foreach((m, s) => mailbox.append(m, s))
- if (null eq qel) {
- synchronized {
- // in mean time new stuff might have arrived
- if (!sendBuffer.isEmpty) {
- tmpMbox = new MQueue[Any]("Temp")
- drainSendBuffer(tmpMbox)
- // keep going
- } else {
- waitingFor = handler
- // see Reactor.searchMailbox
- throw Actor.suspendException
- }
- }
- } else {
- resumeReceiver((qel.msg, qel.session), handler, resumeOnSameThread)
- done = true
- }
- }
- }
-
- private[actors] override def makeReaction(fun: () => Unit, handler: PartialFunction[Any, Any], msg: Any): Runnable =
- new ReplyReactorTask(this, fun, handler, msg)
-
- protected[actors] override def react(handler: PartialFunction[Any, Unit]): Nothing = {
- assert(Actor.rawSelf(scheduler) == this, "react on channel belonging to other actor")
- super.react(handler)
- }
-
- /**
- * Receives a message from this $actor's mailbox within a certain
- * time span.
- *
- * This method never returns. Therefore, the rest of the computation
- * has to be contained in the actions of the partial function.
- *
- * @param msec the time span before timeout
- * @param handler a partial function with message patterns and actions
- */
- protected[actors] def reactWithin(msec: Long)(handler: PartialFunction[Any, Unit]): Nothing = {
- assert(Actor.rawSelf(scheduler) == this, "react on channel belonging to other actor")
-
- synchronized { drainSendBuffer(mailbox) }
-
- // first, remove spurious TIMEOUT message from mailbox if any
- mailbox.extractFirst((m: Any, replyTo: OutputChannel[Any]) => m == TIMEOUT)
-
- while (true) {
- val qel = mailbox.extractFirst((m: Any, replyTo: OutputChannel[Any]) => {
- senders = List(replyTo)
- handler isDefinedAt m
- })
- if (null eq qel) {
- synchronized {
- // in mean time new messages might have arrived
- if (!sendBuffer.isEmpty) {
- drainSendBuffer(mailbox)
- // keep going
- } else if (msec == 0L) {
- // throws Actor.suspendException
- resumeReceiver((TIMEOUT, this), handler, false)
- } else {
- waitingFor = handler
- val thisActor = this
- onTimeout = Some(new TimerTask {
- def run() { thisActor.send(TIMEOUT, thisActor) }
- })
- Actor.timer.schedule(onTimeout.get, msec)
- throw Actor.suspendException
- }
- }
- } else
- resumeReceiver((qel.msg, qel.session), handler, false)
- }
- throw Actor.suspendException
- }
-
- override def getState: Actor.State.Value = synchronized {
- if (waitingFor ne Reactor.waitingForNone) {
- if (onTimeout.isEmpty)
- Actor.State.Suspended
- else
- Actor.State.TimedSuspended
- } else
- _state
- }
-
+@deprecated("Scala Actors are beeing removed from the standard library. Please refer to the migration guide.", "2.10")
+trait ReplyReactor extends InternalReplyReactor {
+
+ protected[actors] def sender: OutputChannel[Any] = super.internalSender
+
}
+
diff --git a/src/actors/scala/actors/ReplyReactorTask.scala b/src/actors/scala/actors/ReplyReactorTask.scala
index cb63d7e000..d38eb50381 100644
--- a/src/actors/scala/actors/ReplyReactorTask.scala
+++ b/src/actors/scala/actors/ReplyReactorTask.scala
@@ -17,13 +17,13 @@ package scala.actors
* changes to the underlying var invisible.) I can't figure out what's supposed
* to happen, so I renamed the constructor parameter to at least be less confusing.
*/
-private[actors] class ReplyReactorTask(replyReactor: ReplyReactor,
+private[actors] class ReplyReactorTask(replyReactor: InternalReplyReactor,
fun: () => Unit,
handler: PartialFunction[Any, Any],
msg: Any)
extends ReactorTask(replyReactor, fun, handler, msg) {
- var saved: ReplyReactor = _
+ var saved: InternalReplyReactor = _
protected override def beginExecution() {
saved = Actor.tl.get
diff --git a/src/actors/scala/actors/UncaughtException.scala b/src/actors/scala/actors/UncaughtException.scala
index 3e6efe3b7c..a3e7f795f1 100644
--- a/src/actors/scala/actors/UncaughtException.scala
+++ b/src/actors/scala/actors/UncaughtException.scala
@@ -20,7 +20,7 @@ package scala.actors
* @author Philipp Haller
* @author Erik Engbrecht
*/
-case class UncaughtException(actor: Actor,
+case class UncaughtException(actor: InternalActor,
message: Option[Any],
sender: Option[OutputChannel[Any]],
thread: Thread,
diff --git a/src/build/maven/continuations-plugin-pom.xml b/src/build/maven/continuations-plugin-pom.xml
index aca519b87e..9abb0a36f0 100644
--- a/src/build/maven/continuations-plugin-pom.xml
+++ b/src/build/maven/continuations-plugin-pom.xml
@@ -23,13 +23,12 @@
</license>
</licenses>
<scm>
- <connection>scm:svn:http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk</connection>
- <url>https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk</url>
+ <connection>scm:git:git://github.com/scala/scala.git</connection>
+ <url>https://github.com/scala/scala.git</url>
</scm>
<issueManagement>
- <system>trac</system>
- <url>http://lampsvn.epfl.ch/trac/scala
- </url>
+ <system>JIRA</system>
+ <url>https://issues.scala-lang.org/</url>
</issueManagement>
<dependencies>
diff --git a/src/build/maven/jline-pom.xml b/src/build/maven/jline-pom.xml
index 4752deb5e0..0d6e801551 100644
--- a/src/build/maven/jline-pom.xml
+++ b/src/build/maven/jline-pom.xml
@@ -28,13 +28,12 @@
</license>
</licenses>
<scm>
- <connection>scm:svn:http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk</connection>
- <url>https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk</url>
+ <connection>scm:git:git://github.com/scala/scala.git</connection>
+ <url>https://github.com/scala/scala.git</url>
</scm>
<issueManagement>
- <system>trac</system>
- <url>http://lampsvn.epfl.ch/trac/scala
- </url>
+ <system>JIRA</system>
+ <url>https://issues.scala-lang.org/</url>
</issueManagement>
<dependencies>
diff --git a/src/build/maven/maven-deploy.xml b/src/build/maven/maven-deploy.xml
index e0f31a5db2..7f8343a84e 100644
--- a/src/build/maven/maven-deploy.xml
+++ b/src/build/maven/maven-deploy.xml
@@ -111,11 +111,12 @@
<deploy-local name="scala-library" version="@{version}" repository="@{repository}" />
<deploy-local name="scala-compiler" version="@{version}" repository="@{repository}" />
<deploy-local-plugin name="continuations" version="@{version}" repository="@{repository}"/>
+ <deploy-local name="scala-actors" version="@{version}" repository="@{repository}" />
<deploy-local name="scala-dbc" version="@{version}" repository="@{repository}" />
<deploy-local name="scala-swing" version="@{version}" repository="@{repository}"/>
- <deploy-local name="scalap" version="@{version}" repository="@{repository}"/>
- <deploy-local name="scala-partest" version="@{version}" repository="@{repository}"/>
- <deploy-local name="jline" version="@{version}" repository="@{repository}"/>
+ <deploy-local name="scalap" version="@{version}" repository="@{repository}"/>
+ <deploy-local name="scala-partest" version="@{version}" repository="@{repository}"/>
+ <deploy-local name="jline" version="@{version}" repository="@{repository}"/>
</sequential>
</macrodef>
</target>
@@ -168,12 +169,13 @@
<artifact:attach type="jar" file="scala-library/scala-library-docs.jar" classifier="javadoc" />
</extra-attachments>
</deploy-remote>
- <deploy-remote name="jline" version="@{version}" repository="@{repository}"/>
+ <deploy-remote name="jline" version="@{version}" repository="@{repository}"/>
<deploy-remote name="scala-compiler" version="@{version}" repository="@{repository}" />
<deploy-remote name="scala-dbc" version="@{version}" repository="@{repository}" />
<deploy-remote name="scala-swing" version="@{version}" repository="@{repository}"/>
- <deploy-remote name="scalap" version="@{version}" repository="@{repository}"/>
- <deploy-remote name="scala-partest" version="@{version}" repository="@{repository}"/>
+ <deploy-remote name="scala-actors" version="@{version}" repository="@{repository}"/>
+ <deploy-remote name="scalap" version="@{version}" repository="@{repository}"/>
+ <deploy-remote name="scala-partest" version="@{version}" repository="@{repository}"/>
<deploy-remote-plugin name="continuations" version="@{version}" repository="@{repository}"/>
</sequential>
</macrodef>
@@ -234,13 +236,14 @@
<attribute name="version" />
<sequential>
<deploy-remote-plugin-signed name="continuations" version="@{version}" repository="@{repository}"/>
- <deploy-remote-signed name="scala-library" version="@{version}" repository="@{repository}"/>
- <deploy-remote-signed name="jline" version="@{version}" repository="@{repository}"/>
+ <deploy-remote-signed name="scala-library" version="@{version}" repository="@{repository}"/>
+ <deploy-remote-signed name="jline" version="@{version}" repository="@{repository}"/>
<deploy-remote-signed name="scala-compiler" version="@{version}" repository="@{repository}" />
<deploy-remote-signed name="scala-dbc" version="@{version}" repository="@{repository}" />
<deploy-remote-signed name="scala-swing" version="@{version}" repository="@{repository}"/>
- <deploy-remote-signed name="scalap" version="@{version}" repository="@{repository}"/>
- <deploy-remote-signed name="scala-partest" version="@{version}" repository="@{repository}"/>
+ <deploy-remote-signed name="scala-actors" version="@{version}" repository="@{repository}"/>
+ <deploy-remote-signed name="scalap" version="@{version}" repository="@{repository}"/>
+ <deploy-remote-signed name="scala-partest" version="@{version}" repository="@{repository}"/>
</sequential>
</macrodef>
</target>
diff --git a/src/build/maven/scala-actors-pom.xml b/src/build/maven/scala-actors-pom.xml
new file mode 100644
index 0000000000..e8c6649721
--- /dev/null
+++ b/src/build/maven/scala-actors-pom.xml
@@ -0,0 +1,61 @@
+<project
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.scala-lang</groupId>
+ <artifactId>scala-actors</artifactId>
+ <packaging>jar</packaging>
+ <version>@VERSION@</version>
+ <name>Scala Actors library</name>
+ <description>Deprecated Actors Library for Scala</description>
+ <url>http://www.scala-lang.org/</url>
+ <inceptionYear>2006</inceptionYear>
+ <organization>
+ <name>LAMP/EPFL</name>
+ <url>http://lamp.epfl.ch/</url>
+ </organization>
+ <licenses>
+ <license>
+ <name>BSD-like</name>
+ <url>http://www.scala-lang.org/downloads/license.html
+ </url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+ <scm>
+ <connection>scm:git:git://github.com/scala/scala.git</connection>
+ <url>https://github.com/scala/scala.git</url>
+ </scm>
+ <issueManagement>
+ <system>JIRA</system>
+ <url>https://issues.scala-lang.org/</url>
+ </issueManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.scala-lang</groupId>
+ <artifactId>scala-library</artifactId>
+ <version>@VERSION@</version>
+ </dependency>
+ </dependencies>
+ <distributionManagement>
+ <repository>
+ <id>scala-tools.org</id>
+ <url>@RELEASE_REPOSITORY@</url>
+ </repository>
+ <snapshotRepository>
+ <id>scala-tools.org</id>
+ <url>@SNAPSHOT_REPOSITORY@</url>
+ <uniqueVersion>false</uniqueVersion>
+ </snapshotRepository>
+ </distributionManagement>
+ <developers>
+ <developer>
+ <id>lamp</id>
+ <name>EPFL LAMP</name>
+ </developer>
+ <developer>
+ <id>Typesafe</id>
+ <name>Typesafe, Inc.</name>
+ </developer>
+ </developers>
+</project>
diff --git a/src/build/maven/scala-compiler-pom.xml b/src/build/maven/scala-compiler-pom.xml
index f9bcb6719d..82d0ed7c91 100644
--- a/src/build/maven/scala-compiler-pom.xml
+++ b/src/build/maven/scala-compiler-pom.xml
@@ -23,13 +23,12 @@
</license>
</licenses>
<scm>
- <connection>scm:svn:http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk</connection>
- <url>https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk</url>
+ <connection>scm:git:git://github.com/scala/scala.git</connection>
+ <url>https://github.com/scala/scala.git</url>
</scm>
<issueManagement>
- <system>trac</system>
- <url>http://lampsvn.epfl.ch/trac/scala
- </url>
+ <system>JIRA</system>
+ <url>https://issues.scala-lang.org/</url>
</issueManagement>
<dependencies>
diff --git a/src/build/maven/scala-dbc-pom.xml b/src/build/maven/scala-dbc-pom.xml
index 23092d10ad..aa3d050c1e 100644
--- a/src/build/maven/scala-dbc-pom.xml
+++ b/src/build/maven/scala-dbc-pom.xml
@@ -23,13 +23,12 @@
</license>
</licenses>
<scm>
- <connection>scm:svn:http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk</connection>
- <url>https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk</url>
+ <connection>scm:git:git://github.com/scala/scala.git</connection>
+ <url>https://github.com/scala/scala.git</url>
</scm>
<issueManagement>
- <system>trac</system>
- <url>http://lampsvn.epfl.ch/trac/scala
- </url>
+ <system>JIRA</system>
+ <url>https://issues.scala-lang.org/</url>
</issueManagement>
<dependencies>
<dependency>
diff --git a/src/build/maven/scala-dotnet-library-pom.xml b/src/build/maven/scala-dotnet-library-pom.xml
index 339460924a..007e8be173 100644
--- a/src/build/maven/scala-dotnet-library-pom.xml
+++ b/src/build/maven/scala-dotnet-library-pom.xml
@@ -24,13 +24,12 @@
</license>
</licenses>
<scm>
- <connection>scm:svn:http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk</connection>
- <url>https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk</url>
+ <connection>scm:git:git://github.com/scala/scala.git</connection>
+ <url>https://github.com/scala/scala.git</url>
</scm>
<issueManagement>
- <system>trac</system>
- <url>http://lampsvn.epfl.ch/trac/scala
- </url>
+ <system>JIRA</system>
+ <url>https://issues.scala-lang.org/</url>
</issueManagement>
<distributionManagement>
<repository>
diff --git a/src/build/maven/scala-library-pom.xml b/src/build/maven/scala-library-pom.xml
index 8e0abd4937..673c3dfada 100644
--- a/src/build/maven/scala-library-pom.xml
+++ b/src/build/maven/scala-library-pom.xml
@@ -23,13 +23,12 @@
</license>
</licenses>
<scm>
- <connection>scm:svn:http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk</connection>
- <url>https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk</url>
+ <connection>scm:git:git://github.com/scala/scala.git</connection>
+ <url>https://github.com/scala/scala.git</url>
</scm>
<issueManagement>
- <system>trac</system>
- <url>http://lampsvn.epfl.ch/trac/scala
- </url>
+ <system>JIRA</system>
+ <url>https://issues.scala-lang.org/</url>
</issueManagement>
<distributionManagement>
<repository>
diff --git a/src/build/maven/scala-partest-pom.xml b/src/build/maven/scala-partest-pom.xml
index f18ca46c50..ac05f242d5 100644
--- a/src/build/maven/scala-partest-pom.xml
+++ b/src/build/maven/scala-partest-pom.xml
@@ -23,13 +23,12 @@
</license>
</licenses>
<scm>
- <connection>scm:svn:http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk</connection>
- <url>https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk</url>
+ <connection>scm:git:git://github.com/scala/scala.git</connection>
+ <url>https://github.com/scala/scala.git</url>
</scm>
<issueManagement>
- <system>trac</system>
- <url>http://lampsvn.epfl.ch/trac/scala
- </url>
+ <system>JIRA</system>
+ <url>https://issues.scala-lang.org/</url>
</issueManagement>
<dependencies>
diff --git a/src/build/maven/scala-swing-pom.xml b/src/build/maven/scala-swing-pom.xml
index a03bc07ab0..3df5db5b21 100644
--- a/src/build/maven/scala-swing-pom.xml
+++ b/src/build/maven/scala-swing-pom.xml
@@ -23,13 +23,12 @@
</license>
</licenses>
<scm>
- <connection>scm:svn:http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk</connection>
- <url>https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk</url>
+ <connection>scm:git:git://github.com/scala/scala.git</connection>
+ <url>https://github.com/scala/scala.git</url>
</scm>
<issueManagement>
- <system>trac</system>
- <url>http://lampsvn.epfl.ch/trac/scala
- </url>
+ <system>JIRA</system>
+ <url>https://issues.scala-lang.org/</url>
</issueManagement>
<dependencies>
<dependency>
diff --git a/src/build/maven/scalap-pom.xml b/src/build/maven/scalap-pom.xml
index d7f867d4a1..50c08e899c 100644
--- a/src/build/maven/scalap-pom.xml
+++ b/src/build/maven/scalap-pom.xml
@@ -23,13 +23,12 @@
</license>
</licenses>
<scm>
- <connection>scm:svn:http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk</connection>
- <url>https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk</url>
+ <connection>scm:git:git://github.com/scala/scala.git</connection>
+ <url>https://github.com/scala/scala.git</url>
</scm>
<issueManagement>
- <system>trac</system>
- <url>http://lampsvn.epfl.ch/trac/scala
- </url>
+ <system>JIRA</system>
+ <url>https://issues.scala-lang.org/</url>
</issueManagement>
<dependencies>
diff --git a/src/build/pack.xml b/src/build/pack.xml
index e79895e3a8..3bd4d7a199 100644
--- a/src/build/pack.xml
+++ b/src/build/pack.xml
@@ -3,14 +3,13 @@
<project name="sabbus-pack">
<description>
- SuperSabbus extension for packaging a distribution to Sbaz or other distribution methods. THIS FILE IS NOT STAND-ALONE AND SHOULD ONLY BE USED THROUGH ENTRY POINTS IN SUPERSABBUS.
+ SuperSabbus extension for packaging a distribution. THIS FILE IS NOT STAND-ALONE AND SHOULD ONLY BE USED THROUGH ENTRY POINTS IN SUPERSABBUS.
</description>
<!-- ===========================================================================
PROPERTIES
============================================================================ -->
- <property name="sbaz.universe" value="http://www.scala-lang.org/downloads/packages"/>
<property file="${basedir}/build.number.maven"/>
<!-- the maven stuff requires version.major, version.minor and version.patch properties.
the "get-scala-revision" script only returns "version.number" -->
@@ -78,6 +77,7 @@ MAIN DISTRIBUTION PACKAGING
<exclude name="logs/**"/>
<exclude name="sandbox/**"/>
<exclude name="test/partest"/>
+ <exclude name=".git"/>
</tarfileset>
<tarfileset dir="${basedir}" prefix="${dist.name}-sources" filemode="755">
<include name="test/partest"/>
@@ -95,111 +95,22 @@ MAIN DISTRIBUTION PACKAGING
</fileset>
</checksum>
</target>
-
- <target name="pack-archives.done" depends="pack-archives.src"/>
-
-<!-- ===========================================================================
-MAIN DISTRIBUTION SBAZ
-============================================================================ -->
-
- <target name="pack-sbaz.start">
- <mkdir dir="${dists.dir}/sbaz"/>
- </target>
-
- <target name="pack-sbaz.lib" depends="pack-sbaz.start">
- <sbaz
- file="${dists.dir}/sbaz/scala-library-${version.number}.sbp"
- adfile="${dists.dir}/sbaz/scala-library-${version.number}.advert"
- name="scala-library"
- version="${version.number}"
- desc="The Scala library. This is the minimal requirement to run any Scala program."
- link="${sbaz.universe}/scala-library-${version.number}.sbp">
- <libset dir="${dist.dir}/lib" includes="scala-library.jar,scala-dbc.jar,scala-swing.jar"/>
- <srcset dir="${dist.dir}/src" includes="scala-library-src.jar,scala-dbc-src.jar,scala-swing-src.jar"/>
- <looseset destination="doc">
- <fileset dir="${dist.dir}/doc" includes="LICENSE,README"/>
- </looseset>
- </sbaz>
- </target>
-
- <target name="pack-sbaz.comp" depends="pack-sbaz.lib">
- <sbaz
- file="${dists.dir}/sbaz/scala-devel-${version.number}.sbp"
- adfile="${dists.dir}/sbaz/scala-devel-${version.number}.advert"
- name="scala-devel"
- version="${version.number}"
- desc="The Scala developer tools. This contains everything that is required to write, test and document new Scala programs."
- depends="scala-library"
- link="${sbaz.universe}/scala-devel-${version.number}.sbp">
- <binset
- dir="${dist.dir}/bin"
- includes="scala,scala.bat,scalac,scalac.bat,scaladoc,scaladoc.bat,fsc,fsc.bat"/>
- <libset dir="${dist.dir}/lib" includes="scala-compiler.jar,jline.jar"/>
- <miscset dir="${dist.dir}/misc/scala-devel"
- includes="plugins/continuations.jar"/>
- <manset dir="${dist.dir}/man" includes="**"/>
- <srcset dir="${dist.dir}/src" includes="scala-compiler-src.jar"/>
- </sbaz>
- </target>
- <target name="pack-sbaz.test" depends="pack-sbaz.comp">
- <sbaz
- file="${dists.dir}/sbaz/scala-test-${version.number}.sbp"
- adfile="${dists.dir}/sbaz/scala-test-${version.number}.advert"
- name="scala-test"
- version="${version.number}"
- desc="The Scala test package contains everything needed to test Scala."
- link="${sbaz.universe}/scala-test-${version.number}.sbp">
- <binset dir="${basedir}/test"
- includes="clitest,diff/diff.*,diff/lib*.dll,partest,partest.bat"/>
- <miscset dir="${basedir}/test"
- includes="files/**/*.args,files/**/*.check,files/**/*.dll,files/**/*.jar,files/**/*.java,files/**/*.scala,files/**/*.flags,files/cli/**/*.check.*,files/jvm/*.so,files/shootout/*.javaopts,files/shootout/*.runner,files/shootout/*.txt,files/specialized/*.txt,files/**/*.test"
- excludes="files/presentation"/>
- <!-- <srcset dir="${dist.dir}/src" includes="scala-partest-src.jar"/> -->
- <libset dir="${dist.dir}/lib" includes="scala-partest.jar"/>
- <libset dir="${lib.dir}" includes="scalacheck.jar"/>
- </sbaz>
- </target>
-
- <target name="pack-sbaz.scalap" depends="pack-sbaz.test">
- <sbaz
- file="${dists.dir}/sbaz/scalap-${version.number}.sbp"
- adfile="${dists.dir}/sbaz/scalap-${version.number}.advert"
- name="scalap"
- version="${version.number}"
- desc="The scalap package contains the Scala classfile decoder."
- link="${sbaz.universe}/scalap-${version.number}.sbp">
- <binset dir="${dist.dir}/bin"
- includes="scalap,scalap.bat"/>
- <libset dir="${dist.dir}/lib" includes="scalap.jar"/>
- </sbaz>
- </target>
-
- <target name="pack-sbaz.doc" depends="pack-sbaz.scalap">
- <sbaz
- file="${dists.dir}/sbaz/scala-devel-docs-${version.number}.sbp"
- adfile="${dists.dir}/sbaz/scala-devel-docs-${version.number}.advert"
- name="scala-devel-docs"
- version="${version.number}"
- desc="The Scala developer documentation. This contains all developer documentation."
- link="${sbaz.universe}/scala-devel-docs-${version.number}.sbp">
- <docset dir="${dist.dir}/doc/scala-devel-docs"/>
- </sbaz>
+ <target name="pack-archives.latest.unix" depends="pack-archives.src" unless="os.win">
+ <symlink link="${dists.dir}/archives/scala-latest-sources.tgz"
+ resource="${dists.dir}/archives/scala-${version.number}-sources.tgz"
+ overwrite="yes"/>
</target>
- <target name="pack-sbaz.all" depends="pack-sbaz.doc">
- <sbaz
- file="${dists.dir}/sbaz/${dist.name}.sbp"
- adfile="${dists.dir}/sbaz/${dist.name}.advert"
- name="scala"
- version="${version.number}"
- desc="The base Scala package that contains everything needed to start using Scala."
- depends="scala-library,scala-devel"
- link="${sbaz.universe}/${dist.name}.sbp"/>
+ <target name="pack-archives.latest.win" depends="pack-archives.src" if="os.win">
+ <copy tofile="${dists.dir}/archives/scala-latest-sources.tgz">
+ <fileset dir="${dists.dir}/archives">
+ <include name="scala-${version.number}-sources.tgz"/>
+ </fileset>
+ </copy>
</target>
-
- <target name="pack-sbaz.done" depends="pack-sbaz.all"/>
+ <target name="pack-archives.done" depends="pack-archives.src, pack-archives.latest.win, pack-archives.latest.unix"/>
<target name="pack-maven.start">
<mkdir dir="${dists.dir}/maven/${version.number}"/>
@@ -228,6 +139,7 @@ MAIN DISTRIBUTION SBAZ
<mvn-copy-lib mvn.artifact.name="scala-compiler"/>
<mvn-copy-lib mvn.artifact.name="scala-dbc"/>
<mvn-copy-lib mvn.artifact.name="scala-swing"/>
+ <mvn-copy-lib mvn.artifact.name="scala-actors"/>
<mvn-copy-lib mvn.artifact.name="scala-partest"/>
<mvn-copy-lib mvn.artifact.name="scalap"/>
</target>
@@ -290,11 +202,13 @@ MAIN DISTRIBUTION SBAZ
basedir="${build-docs.dir}/continuations-plugin">
<include name="**/*"/>
</jar>
- <!-- TODO - Scala swing, dbc should maybe have thier own jar, but creating it is SLOW. -->
+ <!-- TODO - Scala swing, dbc and actors should maybe have thier own jar, but creating it is SLOW. -->
<copy tofile="${dists.dir}/maven/${version.number}/scala-swing/scala-swing-docs.jar"
file="${dists.dir}/maven/${version.number}/scala-library/scala-library-docs.jar"/>
<copy tofile="${dists.dir}/maven/${version.number}/scala-dbc/scala-dbc-docs.jar"
file="${dists.dir}/maven/${version.number}/scala-library/scala-library-docs.jar"/>
+ <copy tofile="${dists.dir}/maven/${version.number}/scala-actors/scala-actors-docs.jar"
+ file="${dists.dir}/maven/${version.number}/scala-library/scala-library-docs.jar"/>
</target>
<target name="pack-maven.latest.unix" depends="pack-maven.docs" unless="os.win">
@@ -324,7 +238,7 @@ MAIN DISTRIBUTION SBAZ
MISCELLANEOUS
============================================================================ -->
- <target name="pack-all.done" depends="pack-archives.done, pack-sbaz.done, pack-maven.done"/>
+ <target name="pack-all.done" depends="pack-archives.done, pack-maven.done"/>
<!-- ===========================================================================
MISCELLANEOUS
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala
index bd823c3128..8ea3cd511a 100644
--- a/src/compiler/scala/reflect/internal/Definitions.scala
+++ b/src/compiler/scala/reflect/internal/Definitions.scala
@@ -138,26 +138,47 @@ trait Definitions extends reflect.api.StandardDefinitions {
// symbols related to packages
var emptypackagescope: Scope = null //debug
- // This is the package _root_. The actual root cannot be referenced at
- // the source level, but _root_ is essentially a function () => <root>.
- lazy val RootPackage: Symbol = {
- val rp = (
- NoSymbol.newValue(nme.ROOTPKG, NoPosition, FINAL | MODULE | PACKAGE | JAVA)
- setInfo NullaryMethodType(RootClass.tpe)
- )
- RootClass.sourceModule = rp
- rp
+ sealed trait WellKnownSymbol extends Symbol {
+ this initFlags TopLevelCreationFlags
+ }
+ // Features common to RootClass and RootPackage, the roots of all
+ // type and term symbols respectively.
+ sealed trait RootSymbol extends WellKnownSymbol {
+ final override def isRootSymbol = true
}
+ // This is the package _root_. The actual root cannot be referenced at
+ // the source level, but _root_ is essentially a function => <root>.
+ final object RootPackage extends ModuleSymbol(NoSymbol, NoPosition, nme.ROOTPKG) with RootSymbol {
+ this setInfo NullaryMethodType(RootClass.tpe)
+ RootClass.sourceModule = this
- // This is the actual root of everything, including the package _root_.
- lazy val RootClass: ModuleClassSymbol = (
- NoSymbol.newModuleClassSymbol(tpnme.ROOT, NoPosition, FINAL | MODULE | PACKAGE | JAVA)
- setInfo rootLoader
- )
+ override def isRootPackage = true
+ }
+ // This is <root>, the actual root of everything except the package _root_.
+ // <root> and _root_ (RootPackage and RootClass) should be the only "well known"
+ // symbols owned by NoSymbol. All owner chains should go through RootClass,
+ // although it is probable that some symbols are created as direct children
+ // of NoSymbol to ensure they will not be stumbled upon. (We should designate
+ // a better encapsulated place for that.)
+ final object RootClass extends ModuleClassSymbol(NoSymbol, NoPosition, tpnme.ROOT) with RootSymbol {
+ this setInfo rootLoader
+
+ override def isRoot = true
+ override def isEffectiveRoot = true
+ override def isStatic = true
+ override def isNestedClass = false
+ override def ownerOfNewSymbols = EmptyPackageClass
+ }
// The empty package, which holds all top level types without given packages.
- lazy val EmptyPackage = RootClass.newPackage(nme.EMPTY_PACKAGE_NAME, NoPosition, FINAL)
- lazy val EmptyPackageClass = EmptyPackage.moduleClass
-
+ final object EmptyPackage extends ModuleSymbol(RootClass, NoPosition, nme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
+ override def isEmptyPackage = true
+ }
+ final object EmptyPackageClass extends ModuleClassSymbol(RootClass, NoPosition, tpnme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
+ override def isEffectiveRoot = true
+ override def isEmptyPackageClass = true
+ }
+ // It becomes tricky to create dedicated objects for other symbols because
+ // of initialization order issues.
lazy val JavaLangPackage = getModule(sn.JavaLang)
lazy val JavaLangPackageClass = JavaLangPackage.moduleClass
lazy val ScalaPackage = getModule(nme.scala_)
@@ -524,26 +545,54 @@ trait Definitions extends reflect.api.StandardDefinitions {
else nme.genericWrapArray
}
+ @deprecated("Use isTupleType", "2.10.0")
+ def isTupleTypeOrSubtype(tp: Type): Boolean = isTupleType(tp)
+
def tupleField(n: Int, j: Int) = getMember(TupleClass(n), nme.productAccessorName(j))
- def isTupleType(tp: Type): Boolean = isTupleType(tp, false)
- def isTupleTypeOrSubtype(tp: Type): Boolean = isTupleType(tp, true)
- private def isTupleType(tp: Type, subtypeOK: Boolean) = tp.normalize match {
- case TypeRef(_, sym, args) if args.nonEmpty =>
- val len = args.length
- len <= MaxTupleArity && {
- val tsym = TupleClass(len)
- (sym == tsym) || (subtypeOK && !tp.isHigherKinded && sym.isSubClass(tsym))
- }
- case _ => false
+ def isTupleSymbol(sym: Symbol) = TupleClass contains unspecializedSymbol(sym)
+
+ def unspecializedSymbol(sym: Symbol): Symbol = {
+ if (sym hasFlag SPECIALIZED) {
+ // add initialization from its generic class constructor
+ val genericName = nme.unspecializedName(sym.name)
+ val member = sym.owner.info.decl(genericName.toTypeName)
+ member
}
+ else sym
+ }
- def tupleType(elems: List[Type]) = {
- val len = elems.length
- if (len <= MaxTupleArity) {
- val sym = TupleClass(len)
- typeRef(sym.typeConstructor.prefix, sym, elems)
- } else NoType
- }
+ // Checks whether the given type is true for the given condition,
+ // or if it is a specialized subtype of a type for which it is true.
+ //
+ // Origins notes:
+ // An issue was introduced with specialization in that the implementation
+ // of "isTupleType" in Definitions relied upon sym == TupleClass(elems.length).
+ // This test is untrue for specialized tuples, causing mysterious behavior
+ // because only some tuples are specialized.
+ def isPossiblySpecializedType(tp: Type)(cond: Type => Boolean) = {
+ cond(tp) || (tp match {
+ case TypeRef(pre, sym, args) if sym hasFlag SPECIALIZED =>
+ cond(tp baseType unspecializedSymbol(sym))
+ case _ =>
+ false
+ })
+ }
+ // No normalization.
+ def isTupleTypeDirect(tp: Type) = isPossiblySpecializedType(tp) {
+ case TypeRef(_, sym, args) if args.nonEmpty =>
+ val len = args.length
+ len <= MaxTupleArity && sym == TupleClass(len)
+ case _ => false
+ }
+ def isTupleType(tp: Type) = isTupleTypeDirect(tp.normalize)
+
+ def tupleType(elems: List[Type]) = {
+ val len = elems.length
+ if (len <= MaxTupleArity) {
+ val sym = TupleClass(len)
+ typeRef(sym.typeConstructor.prefix, sym, elems)
+ } else NoType
+ }
lazy val ProductRootClass: Symbol = getRequiredClass("scala.Product")
def Product_productArity = getMember(ProductRootClass, nme.productArity)
@@ -601,8 +650,8 @@ trait Definitions extends reflect.api.StandardDefinitions {
def isFunctionType(tp: Type): Boolean = tp.normalize match {
case TypeRef(_, sym, args) if args.nonEmpty =>
- val len = args.length
- len < MaxFunctionArity && sym == FunctionClass(len - 1)
+ val arity = args.length - 1 // -1 is the return type
+ arity <= MaxFunctionArity && sym == FunctionClass(arity)
case _ =>
false
}
@@ -764,9 +813,25 @@ trait Definitions extends reflect.api.StandardDefinitions {
else
removeRedundantObjects(parents)
}
+
+ def typeStringNoPackage(tp: Type) =
+ "" + tp stripPrefix tp.typeSymbol.enclosingPackage.fullName + "."
+
+ def briefParentsString(parents: List[Type]) =
+ normalizedParents(parents) map typeStringNoPackage mkString " with "
+
def parentsString(parents: List[Type]) =
normalizedParents(parents) mkString " with "
+ def typeParamsString(tp: Type) = tp match {
+ case PolyType(tparams, _) => tparams map (_.defString) mkString ("[", ",", "]")
+ case _ => ""
+ }
+ def valueParamsString(tp: Type) = tp match {
+ case MethodType(params, _) => params map (_.defString) mkString ("(", ",", ")")
+ case _ => ""
+ }
+
// members of class java.lang.{ Object, String }
lazy val Object_## = enterNewMethod(ObjectClass, nme.HASHHASH, Nil, inttype, FINAL)
lazy val Object_== = enterNewMethod(ObjectClass, nme.EQ, anyrefparam, booltype, FINAL)
@@ -970,7 +1035,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
case (_, restpe) => NullaryMethodType(restpe)
}
- msym setInfoAndEnter polyType(tparams, mtpe)
+ msym setInfoAndEnter genPolyType(tparams, mtpe)
}
/** T1 means one type parameter.
@@ -1074,9 +1139,14 @@ trait Definitions extends reflect.api.StandardDefinitions {
def init() {
if (isInitialized) return
+ // Still fiddling with whether it's cleaner to do some of this setup here
+ // or from constructors. The latter approach tends to invite init order issues.
EmptyPackageClass setInfo ClassInfoType(Nil, newPackageScope(EmptyPackageClass), EmptyPackageClass)
EmptyPackage setInfo EmptyPackageClass.tpe
+ connectModuleToClass(EmptyPackage, EmptyPackageClass)
+ connectModuleToClass(RootPackage, RootClass)
+
RootClass.info.decls enter EmptyPackage
RootClass.info.decls enter RootPackage
diff --git a/src/compiler/scala/reflect/internal/Flags.scala b/src/compiler/scala/reflect/internal/Flags.scala
index 8aae80eed4..ce1c8d0908 100644
--- a/src/compiler/scala/reflect/internal/Flags.scala
+++ b/src/compiler/scala/reflect/internal/Flags.scala
@@ -84,7 +84,7 @@ import scala.collection.{ mutable, immutable }
*/
class ModifierFlags {
final val IMPLICIT = 0x00000200
- final val FINAL = 0x00000020
+ final val FINAL = 0x00000020 // May not be overridden. Note that java final implies much more than scala final.
final val PRIVATE = 0x00000004
final val PROTECTED = 0x00000001
@@ -107,7 +107,7 @@ class ModifierFlags {
// pre: PRIVATE or PROTECTED are also set
final val JAVA = 0x00100000 // symbol was defined by a Java class
final val STATIC = 0x00800000 // static field, method or class
- final val CASEACCESSOR = 0x01000000 // symbol is a case parameter (or its accessor)
+ final val CASEACCESSOR = 0x01000000 // symbol is a case parameter (or its accessor, or a GADT skolem)
final val TRAIT = 0x02000000 // symbol is a trait
final val DEFAULTPARAM = 0x02000000 // the parameter has a default value
final val PARAMACCESSOR = 0x20000000 // for field definitions generated for primary constructor
diff --git a/src/compiler/scala/reflect/internal/Importers.scala b/src/compiler/scala/reflect/internal/Importers.scala
index 1003fa804f..04381937d1 100644
--- a/src/compiler/scala/reflect/internal/Importers.scala
+++ b/src/compiler/scala/reflect/internal/Importers.scala
@@ -351,6 +351,8 @@ trait Importers { self: SymbolTable =>
new ApplyToImplicitArgs(importTree(fun), args map importTree)
case _: from.ApplyImplicitView =>
new ApplyImplicitView(importTree(fun), args map importTree)
+ case _: from.ApplyConstructor =>
+ new ApplyConstructor(importTree(fun), args map importTree)
case _ =>
new Apply(importTree(fun), args map importTree)
}
diff --git a/src/compiler/scala/reflect/internal/Kinds.scala b/src/compiler/scala/reflect/internal/Kinds.scala
index 23bff950b8..eca63c7c15 100644
--- a/src/compiler/scala/reflect/internal/Kinds.scala
+++ b/src/compiler/scala/reflect/internal/Kinds.scala
@@ -49,9 +49,15 @@ trait Kinds {
private def kindMessage(a: Symbol, p: Symbol)(f: (String, String) => String): String =
f(a+qualify(a,p), p+qualify(p,a))
+ // Normally it's nicer to print nothing rather than '>: Nothing <: Any' all over
+ // the place, but here we need it for the message to make sense.
private def strictnessMessage(a: Symbol, p: Symbol) =
- kindMessage(a, p)("%s's bounds %s are stricter than %s's declared bounds %s".format(
- _, a.info, _, p.info))
+ kindMessage(a, p)("%s's bounds%s are stricter than %s's declared bounds%s".format(
+ _, a.info, _, p.info match {
+ case tb @ TypeBounds(_, _) if tb.isEmptyBounds => " >: Nothing <: Any"
+ case tb => "" + tb
+ })
+ )
private def varianceMessage(a: Symbol, p: Symbol) =
kindMessage(a, p)("%s is %s, but %s is declared %s".format(_, varStr(a), _, varStr(p)))
@@ -62,11 +68,16 @@ trait Kinds {
_, countAsString(p.typeParams.length))
)
+ private def buildMessage(xs: List[SymPair], f: (Symbol, Symbol) => String) = (
+ if (xs.isEmpty) ""
+ else xs map f.tupled mkString ("\n", ", ", "")
+ )
+
def errorMessage(targ: Type, tparam: Symbol): String = (
- (targ+"'s type parameters do not match "+tparam+"'s expected parameters: ")
- + (arity map { case (a, p) => arityMessage(a, p) } mkString ", ")
- + (variance map { case (a, p) => varianceMessage(a, p) } mkString ", ")
- + (strictness map { case (a, p) => strictnessMessage(a, p) } mkString ", ")
+ (targ+"'s type parameters do not match "+tparam+"'s expected parameters:")
+ + buildMessage(arity, arityMessage)
+ + buildMessage(variance, varianceMessage)
+ + buildMessage(strictness, strictnessMessage)
)
}
val NoKindErrors = KindErrors(Nil, Nil, Nil)
diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala
index 84007425ed..e2c253628c 100644
--- a/src/compiler/scala/reflect/internal/StdNames.scala
+++ b/src/compiler/scala/reflect/internal/StdNames.scala
@@ -283,13 +283,13 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val TYPE_ : NameType = "TYPE"
val TypeTree: NameType = "TypeTree"
val UNIT : NameType = "UNIT"
- val _isDefinedAt: NameType = "_isDefinedAt"
val add_ : NameType = "add"
val annotation: NameType = "annotation"
val anyValClass: NameType = "anyValClass"
val append: NameType = "append"
val apply: NameType = "apply"
val applyDynamic: NameType = "applyDynamic"
+ val applyOrElse: NameType = "applyOrElse"
val args : NameType = "args"
val argv : NameType = "argv"
val arrayValue: NameType = "arrayValue"
@@ -357,7 +357,6 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val main: NameType = "main"
val map: NameType = "map"
val mirror : NameType = "mirror"
- val missingCase: NameType = "missingCase"
val ne: NameType = "ne"
val newArray: NameType = "newArray"
val newScopeWith: NameType = "newScopeWith"
@@ -405,6 +404,8 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val withFilter: NameType = "withFilter"
val zip: NameType = "zip"
+ val synthSwitch: NameType = "$synthSwitch"
+
// unencoded operators
object raw {
final val AMP : NameType = "&"
diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala
index b58a0ef7d5..bb11ca634a 100644
--- a/src/compiler/scala/reflect/internal/SymbolTable.scala
+++ b/src/compiler/scala/reflect/internal/SymbolTable.scala
@@ -55,6 +55,12 @@ abstract class SymbolTable extends api.Universe
log(msg + ": " + result)
result
}
+ private[scala] def logResultIf[T](msg: String, cond: T => Boolean)(result: T): T = {
+ if (cond(result))
+ log(msg + ": " + result)
+
+ result
+ }
/** Are we compiling for Java SE? */
// def forJVM: Boolean
diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala
index 9678d2b8cd..4473d63f5f 100644
--- a/src/compiler/scala/reflect/internal/Symbols.scala
+++ b/src/compiler/scala/reflect/internal/Symbols.scala
@@ -269,11 +269,17 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** Create a new existential type skolem with this symbol its owner,
* based on the given symbol and origin.
*/
- def newExistentialSkolem(basis: Symbol, origin: AnyRef, name: TypeName = null, info: Type = null): TypeSkolem = {
- val skolem = newTypeSkolemSymbol(if (name eq null) basis.name.toTypeName else name, origin, basis.pos, (basis.flags | EXISTENTIAL) & ~PARAM)
- skolem setInfo (if (info eq null) basis.info cloneInfo skolem else info)
+ def newExistentialSkolem(basis: Symbol, origin: AnyRef): TypeSkolem = {
+ val skolem = newTypeSkolemSymbol(basis.name.toTypeName, origin, basis.pos, (basis.flags | EXISTENTIAL) & ~PARAM)
+ skolem setInfo (basis.info cloneInfo skolem)
}
+ // flags set up to maintain TypeSkolem's invariant: origin.isInstanceOf[Symbol] == !hasFlag(EXISTENTIAL)
+ // CASEACCESSOR | SYNTHETIC used to single this symbol out in deskolemizeGADT
+ def newGADTSkolem(name: TypeName, origin: Symbol, info: Type): TypeSkolem =
+ newTypeSkolemSymbol(name, origin, origin.pos, origin.flags & ~(EXISTENTIAL | PARAM) | CASEACCESSOR | SYNTHETIC) setInfo info
+
+
final def newExistential(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): Symbol =
newAbstractType(name, pos, EXISTENTIAL | newFlags)
@@ -445,12 +451,23 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def isVarargsMethod = isMethod && hasFlag(VARARGS)
/** Package tests */
- final def isEmptyPackage = isPackage && name == nme.EMPTY_PACKAGE_NAME
- final def isEmptyPackageClass = isPackageClass && name == tpnme.EMPTY_PACKAGE_NAME
final def isPackage = isModule && hasFlag(PACKAGE)
final def isPackageClass = isClass && hasFlag(PACKAGE)
- final def isRoot = isPackageClass && owner == NoSymbol
- final def isRootPackage = isPackage && owner == NoSymbol
+
+ /** Overridden in custom objects in Definitions */
+ def isRoot = false
+ def isRootPackage = false
+ def isRootSymbol = false // RootPackage and RootClass. TODO: also NoSymbol.
+ def isEmptyPackage = false
+ def isEmptyPackageClass = false
+
+ /** Is this symbol an effective root for fullname string?
+ */
+ def isEffectiveRoot = false
+
+ /** For RootClass, EmptyPackageClass. For all other symbols, itself.
+ */
+ def ownerOfNewSymbols = this
/** Does this symbol denote a wrapper created by the repl? */
final def isInterpreterWrapper = (
@@ -458,9 +475,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
&& owner.isPackageClass
&& nme.isReplWrapperName(name)
)
- /** Is this symbol an effective root for fullname string?
- */
- def isEffectiveRoot = isRoot || isEmptyPackageClass
/** Term symbols with the exception of static parts of Java classes and packages.
*/
@@ -495,6 +509,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// List[T] forSome { type T }
final def isExistentialSkolem = isExistentiallyBound && isSkolem
final def isExistentialQuantified = isExistentiallyBound && !isSkolem
+ final def isGADTSkolem = isSkolem && hasFlag(CASEACCESSOR | SYNTHETIC)
// class C extends D( { class E { ... } ... } ). Here, E is a class local to a constructor
final def isClassLocalToConstructor = isClass && hasFlag(INCONSTRUCTOR)
@@ -536,7 +551,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** Conditions where we omit the prefix when printing a symbol, to avoid
* unpleasantries like Predef.String, $iw.$iw.Foo and <empty>.Bippy.
*/
- final def isOmittablePrefix = !settings.debug.value && (
+ final def isOmittablePrefix = /*!settings.debug.value &&*/ (
UnqualifiedOwners(skipPackageObject)
|| isEmptyPrefix
)
@@ -645,8 +660,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def isModuleVar = hasFlag(MODULEVAR)
/** Is this symbol static (i.e. with no outer instance)? */
- final def isStatic: Boolean =
- hasFlag(STATIC) || isRoot || owner.isStaticOwner
+ def isStatic = (this hasFlag STATIC) || owner.isStaticOwner
/** Is this symbol a static constructor? */
final def isStaticConstructor: Boolean =
@@ -678,8 +692,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def isConstant: Boolean = isStable && isConstantType(tpe.resultType)
/** Is this class nested in another class or module (not a package)? */
- final def isNestedClass: Boolean =
- isClass && !isRoot && !owner.isPackageClass
+ def isNestedClass = isClass && !owner.isPackageClass
/** Is this class locally defined?
* A class is local, if
@@ -1184,9 +1197,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
var ph = phase
while (ph.prev.keepsTypeParams)
ph = ph.prev
-
- if (ph ne phase)
- debuglog("checking unsafeTypeParams(" + this + ") at: " + phase + " reading at: " + ph)
+ //
+ // if (ph ne phase)
+ // debuglog("checking unsafeTypeParams(" + this + ") at: " + phase + " reading at: " + ph)
ph
}
@@ -1865,7 +1878,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def unpackLocation: AnyRef = null
/** Remove private modifier from symbol `sym`s definition. If `sym` is a
- * term symbol rename it by expanding its name to avoid name clashes
+ * is not a constructor nor a static module rename it by expanding its name to avoid name clashes
+ * @param base the fully qualified name of this class will be appended if name expansion is needed
*/
final def makeNotPrivate(base: Symbol) {
if (this.isPrivate) {
@@ -1985,6 +1999,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
else if (isTrait) ("trait", "trait", "TRT")
else if (isClass) ("class", "class", "CLS")
else if (isType) ("type", "type", "TPE")
+ else if (isClassConstructor && isPrimaryConstructor) ("primary constructor", "constructor", "PCTOR")
else if (isClassConstructor) ("constructor", "constructor", "CTOR")
else if (isSourceMethod) ("method", "method", "METH")
else if (isTerm) ("value", "value", "VAL")
@@ -2036,7 +2051,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def fullNameString: String = {
def recur(sym: Symbol): String = {
- if (sym.isRoot || sym.isRootPackage || sym == NoSymbol) sym.nameString
+ if (sym.isRootSymbol || sym == NoSymbol) sym.nameString
else if (sym.owner.isEffectiveRoot) sym.nameString
else recur(sym.effectiveOwner.enclClass) + "." + sym.nameString
}
@@ -2070,47 +2085,32 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
case s => " in " + s
}
def fullLocationString: String = toString + locationString
- def signatureString: String = if (hasRawInfo) infoString(rawInfo) else "<_>"
+ def signatureString: String = if (hasRawInfo) infoString(rawInfo) else "<_>"
/** String representation of symbol's definition following its name */
final def infoString(tp: Type): String = {
- def typeParamsString: String = tp match {
- case PolyType(tparams, _) if tparams.nonEmpty =>
- (tparams map (_.defString)).mkString("[", ",", "]")
- case _ =>
- ""
- }
- if (isClass)
- typeParamsString + " extends " + tp.resultType
- else if (isAliasType)
- typeParamsString + " = " + tp.resultType
- else if (isAbstractType)
- typeParamsString + {
- tp.resultType match {
- case TypeBounds(lo, hi) =>
- (if (lo.typeSymbol == NothingClass) "" else " >: " + lo) +
- (if (hi.typeSymbol == AnyClass) "" else " <: " + hi)
- case rtp =>
- "<: " + rtp
- }
- }
- else if (isModule)
- moduleClass.infoString(tp)
- else
- tp match {
- case PolyType(tparams, res) =>
- typeParamsString + infoString(res)
- case NullaryMethodType(res) =>
- infoString(res)
- case MethodType(params, res) =>
- params.map(_.defString).mkString("(", ",", ")") + infoString(res)
- case _ =>
- ": " + tp
+ def parents = (
+ if (settings.debug.value) parentsString(tp.parents)
+ else briefParentsString(tp.parents)
+ )
+ if (isType) typeParamsString(tp) + (
+ if (isClass) " extends " + parents
+ else if (isAliasType) " = " + tp.resultType
+ else tp.resultType match {
+ case rt @ TypeBounds(_, _) => "" + rt
+ case rt => " <: " + rt
}
+ )
+ else if (isModule) "" // avoid "object X of type X.type"
+ else tp match {
+ case PolyType(tparams, res) => typeParamsString(tp) + infoString(res)
+ case NullaryMethodType(res) => infoString(res)
+ case MethodType(params, res) => valueParamsString(tp) + infoString(res)
+ case _ => ": " + tp
+ }
}
- def infosString = infos.toString()
-
+ def infosString = infos.toString
def debugLocationString = fullLocationString + " " + debugFlagString
def debugFlagString = hasFlagsToString(-1L)
def hasFlagsToString(mask: Long): String = flagsToString(
@@ -2125,16 +2125,22 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
else ""
def defaultFlagMask =
- if (settings.debug.value) -1L
+ if (isAbstractType) ExplicitFlags
+ else if (settings.debug.value) -1L
else if (owner.isRefinementClass) ExplicitFlags & ~OVERRIDE
else ExplicitFlags
+ // make the error message more googlable
+ def flagsExplanationString =
+ if (isGADTSkolem) " (this is a GADT skolem)"
+ else ""
+
def accessString = hasFlagsToString(PRIVATE | PROTECTED | LOCAL)
def defaultFlagString = hasFlagsToString(defaultFlagMask)
private def defStringCompose(infoString: String) = compose(
defaultFlagString,
keyString,
- varianceString + nameString + infoString
+ varianceString + nameString + infoString + flagsExplanationString
)
/** String representation of symbol's definition. It uses the
* symbol's raw info to avoid forcing types.
@@ -2477,7 +2483,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* where the skolem was introduced (this is important for knowing when to pack it
* again into ab Existential). origin is `null` only in skolemizeExistentials called
* from <:< or isAsSpecific, because here its value does not matter.
- * I elieve the following invariant holds:
+ * I believe the following invariant holds:
*
* origin.isInstanceOf[Symbol] == !hasFlag(EXISTENTIAL)
*/
@@ -2671,7 +2677,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def rawInfo: Type = NoType
protected def doCookJavaRawInfo() {}
override def accessBoundary(base: Symbol): Symbol = RootClass
- def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol = abort()
+ def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol = abort("NoSymbol.clone()")
override def originalEnclosingMethod = this
override def owner: Symbol =
diff --git a/src/compiler/scala/reflect/internal/TreeInfo.scala b/src/compiler/scala/reflect/internal/TreeInfo.scala
index 769d7a9ed1..ce3de94335 100644
--- a/src/compiler/scala/reflect/internal/TreeInfo.scala
+++ b/src/compiler/scala/reflect/internal/TreeInfo.scala
@@ -17,7 +17,7 @@ abstract class TreeInfo {
val global: SymbolTable
import global._
- import definitions.{ isVarArgsList, isCastSymbol, ThrowableClass }
+ import definitions.{ isVarArgsList, isCastSymbol, ThrowableClass, TupleClass }
/* Does not seem to be used. Not sure what it does anyway.
def isOwnerDefinition(tree: Tree): Boolean = tree match {
@@ -312,6 +312,24 @@ abstract class TreeInfo {
case _ => false
}
+ /** Is this tree comprised of nothing but identifiers,
+ * but possibly in bindings or tuples? For instance
+ *
+ * foo @ (bar, (baz, quux))
+ *
+ * is a variable pattern; if the structure matches,
+ * then the remainder is inevitable.
+ */
+ def isVariablePattern(tree: Tree): Boolean = tree match {
+ case Bind(name, pat) => isVariablePattern(pat)
+ case Ident(name) => true
+ case Apply(sel, args) =>
+ ( isReferenceToScalaMember(sel, TupleClass(args.size).name.toTermName)
+ && (args forall isVariablePattern)
+ )
+ case _ => false
+ }
+
/** Is this argument node of the form <expr> : _* ?
*/
def isWildcardStarArg(tree: Tree): Boolean = tree match {
diff --git a/src/compiler/scala/reflect/internal/TreePrinters.scala b/src/compiler/scala/reflect/internal/TreePrinters.scala
index f823110440..8ed0ee6357 100644
--- a/src/compiler/scala/reflect/internal/TreePrinters.scala
+++ b/src/compiler/scala/reflect/internal/TreePrinters.scala
@@ -433,7 +433,7 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable =>
/** Hook for extensions */
def xprintTree(treePrinter: TreePrinter, tree: Tree) =
- treePrinter.print(tree.productPrefix+tree.productIterator.mkString("(", ", ", ")"))
+ treePrinter.print(tree.printingPrefix+tree.productIterator.mkString("(", ", ", ")"))
def newTreePrinter(writer: PrintWriter): TreePrinter = new TreePrinter(writer)
def newTreePrinter(stream: OutputStream): TreePrinter = newTreePrinter(new PrintWriter(stream))
diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala
index 9b1712b790..1a40e0105c 100644
--- a/src/compiler/scala/reflect/internal/Trees.scala
+++ b/src/compiler/scala/reflect/internal/Trees.scala
@@ -350,8 +350,9 @@ trait Trees extends api.Trees { self: SymbolTable =>
"subst[%s, %s](%s)".format(fromStr, toStr, (from, to).zipped map (_ + " -> " + _) mkString ", ")
}
- // NOTE: if symbols in `from` occur multiple times in the `tree` passed to `transform`,
- // the resulting Tree will be a graph, not a tree... this breaks all sorts of stuff,
+ // NOTE: calls shallowDuplicate on trees in `to` to avoid problems when symbols in `from`
+ // occur multiple times in the `tree` passed to `transform`,
+ // otherwise, the resulting Tree would be a graph, not a tree... this breaks all sorts of stuff,
// notably concerning the mutable aspects of Trees (such as setting their .tpe)
class TreeSubstituter(from: List[Symbol], to: List[Tree]) extends Transformer {
override def transform(tree: Tree): Tree = tree match {
diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala
index 2382413a9a..5afa5343ed 100644
--- a/src/compiler/scala/reflect/internal/Types.scala
+++ b/src/compiler/scala/reflect/internal/Types.scala
@@ -97,7 +97,7 @@ trait Types extends api.Types { self: SymbolTable =>
*/
private final val propagateParameterBoundsToTypeVars = sys.props contains "scalac.debug.prop-constraints"
- protected val enableTypeVarExperimentals = settings.Xexperimental.value
+ protected val enableTypeVarExperimentals = settings.Xexperimental.value || settings.YvirtPatmat.value
/** Empty immutable maps to avoid allocations. */
private val emptySymMap = immutable.Map[Symbol, Symbol]()
@@ -448,7 +448,7 @@ trait Types extends api.Types { self: SymbolTable =>
def resultType(actuals: List[Type]) = this
/** Only used for dependent method types. */
- def resultApprox: Type = ApproximateDependentMap(resultType) // if (!settings.YdepMethTpes.value) resultType else
+ def resultApprox: Type = ApproximateDependentMap(resultType)
/** If this is a TypeRef `clazz`[`T`], return the argument `T`
* otherwise return this type
@@ -904,6 +904,12 @@ trait Types extends api.Types { self: SymbolTable =>
else str
}
+ /** The string representation of this type when the direct object in a sentence.
+ * Normally this is no different from the regular representation, but modules
+ * read better as "object Foo" here and "Foo.type" the rest of the time.
+ */
+ def directObjectString = safeToString
+
/** A test whether a type contains any unification type variables. */
def isGround: Boolean = this match {
case TypeVar(_, constr) =>
@@ -1041,8 +1047,8 @@ trait Types extends api.Types { self: SymbolTable =>
baseClasses.head.newOverloaded(this, members.toList)
}
}
- /** The existential skolems and existentially quantified variables which are free in this type */
- def existentialSkolems: List[Symbol] = {
+ /** The (existential or otherwise) skolems and existentially quantified variables which are free in this type */
+ def skolemsExceptMethodTypeParams: List[Symbol] = {
var boundSyms: List[Symbol] = List()
var skolems: List[Symbol] = List()
for (t <- this) {
@@ -1050,7 +1056,8 @@ trait Types extends api.Types { self: SymbolTable =>
case ExistentialType(quantified, qtpe) =>
boundSyms = boundSyms ::: quantified
case TypeRef(_, sym, _) =>
- if ((sym hasFlag EXISTENTIAL) && !(boundSyms contains sym) && !(skolems contains sym))
+ if ((sym.isExistentialSkolem || sym.isGADTSkolem) && // treat GADT skolems like existential skolems
+ !((boundSyms contains sym) || (skolems contains sym)))
skolems = sym :: skolems
case _ =>
}
@@ -1223,8 +1230,7 @@ trait Types extends api.Types { self: SymbolTable =>
else if (sym.isModuleClass) sym.fullNameString + "."
else sym.nameString + ".this."
override def safeToString: String =
- if (sym.isRoot) "<root>"
- else if (sym.isEmptyPackageClass) "<empty>"
+ if (sym.isEffectiveRoot) "" + sym.name
else super.safeToString
override def narrow: Type = this
override def kind = "ThisType"
@@ -1336,9 +1342,14 @@ trait Types extends api.Types { self: SymbolTable =>
case TypeBounds(_, _) => that <:< this
case _ => lo <:< that && that <:< hi
}
- def isEmptyBounds = (lo.typeSymbolDirect eq NothingClass) && (hi.typeSymbolDirect eq AnyClass)
+ private def lowerString = if (emptyLowerBound) "" else " >: " + lo
+ private def upperString = if (emptyUpperBound) "" else " <: " + hi
+ private def emptyLowerBound = lo.typeSymbolDirect eq NothingClass
+ private def emptyUpperBound = hi.typeSymbolDirect eq AnyClass
+ def isEmptyBounds = emptyLowerBound && emptyUpperBound
+
// override def isNullable: Boolean = NullClass.tpe <:< lo;
- override def safeToString = ">: " + lo + " <: " + hi
+ override def safeToString = lowerString + upperString
override def kind = "TypeBoundsType"
}
@@ -1845,6 +1856,35 @@ trait Types extends api.Types { self: SymbolTable =>
// advantage to call TypeRef directly.
override def typeConstructor = TypeRef(pre, sym, Nil)
}
+
+ class ModuleTypeRef(pre0: Type, sym0: Symbol) extends NoArgsTypeRef(pre0, sym0) with ClassTypeRef {
+ require(sym.isModuleClass, sym)
+ private[this] var narrowedCache: Type = _
+ override def isStable = true
+ override def narrow = {
+ if (narrowedCache eq null)
+ narrowedCache = singleType(pre, sym.sourceModule)
+
+ narrowedCache
+ }
+ final override def isNotNull = true
+ override protected def finishPrefix(rest: String) = objectPrefix + rest
+ override def directObjectString = super.safeToString
+ override def toLongString = toString
+ override def safeToString = narrow.toString
+ }
+ class PackageTypeRef(pre0: Type, sym0: Symbol) extends ModuleTypeRef(pre0, sym0) {
+ require(sym.isPackageClass, sym)
+ override protected def finishPrefix(rest: String) = packagePrefix + rest
+ }
+ class RefinementTypeRef(sym0: Symbol) extends NoArgsTypeRef(NoType, sym0) with ClassTypeRef {
+ require(sym.isRefinementClass, sym)
+
+ // I think this is okay, but see #1241 (r12414), #2208, and typedTypeConstructor in Typers
+ override protected def normalizeImpl: Type = sym.info.normalize
+ override protected def finishPrefix(rest: String) = "" + thisInfo
+ }
+
class NoArgsTypeRef(pre0: Type, sym0: Symbol) extends TypeRef(pre0, sym0, Nil) with UniqueType {
// A reference (in a Scala program) to a type that has type parameters, but where the reference
// does not include type arguments. Note that it doesn't matter whether the symbol refers
@@ -1892,10 +1932,6 @@ trait Types extends api.Types { self: SymbolTable =>
// !!! There are scaladoc-created symbols arriving which violate this require.
// require(sym.isClass, sym)
- override protected def normalizeImpl: Type =
- if (sym.isRefinementClass) sym.info.normalize // I think this is okay, but see #1241 (r12414), #2208, and typedTypeConstructor in Typers
- else super.normalizeImpl
-
override def baseType(clazz: Symbol): Type =
if (sym == clazz) this
else transform(sym.info.baseType(clazz))
@@ -2141,12 +2177,15 @@ trait Types extends api.Types { self: SymbolTable =>
}
}
- private def preString = (
- // ensure that symbol is not a local copy with a name coincidence
- if (!settings.debug.value && shorthands(sym.fullName) && sym.ownerChain.forall(_.isClass)) ""
- else pre.prefixString
+ // ensure that symbol is not a local copy with a name coincidence
+ private def needsPreString = (
+ settings.debug.value
+ || !shorthands(sym.fullName)
+ || sym.ownerChain.exists(s => !s.isClass)
)
+ private def preString = if (needsPreString) pre.prefixString else ""
private def argsString = if (args.isEmpty) "" else args.mkString("[", ",", "]")
+
def refinementString = (
if (sym.isStructuralRefinement) (
decls filter (sym => sym.isPossibleInRefinement && sym.isPublic)
@@ -2156,25 +2195,23 @@ trait Types extends api.Types { self: SymbolTable =>
else ""
)
- private def finishPrefix(rest: String) = (
- if (sym.isPackageClass) packagePrefix + rest
- else if (sym.isModuleClass) objectPrefix + rest
- else if (!sym.isInitialized) rest
- else if (sym.isAnonymousClass && !phase.erasedTypes) parentsString(thisInfo.parents) + refinementString
- else if (sym.isRefinementClass) "" + thisInfo
+ protected def finishPrefix(rest: String) = (
+ if (sym.isInitialized && sym.isAnonymousClass && !phase.erasedTypes)
+ parentsString(thisInfo.parents) + refinementString
else rest
)
private def customToString = this match {
case TypeRef(_, RepeatedParamClass, arg :: _) => arg + "*"
case TypeRef(_, ByNameParamClass, arg :: _) => "=> " + arg
case _ =>
+ def targs = normalize.typeArgs
+
if (isFunctionType(this)) {
- val targs = normalize.typeArgs
// Aesthetics: printing Function1 as T => R rather than (T) => R
// ...but only if it's not a tuple, so ((T1, T2)) => R is distinguishable
// from (T1, T2) => R.
targs match {
- case in :: out :: Nil if !isTupleTypeOrSubtype(in) =>
+ case in :: out :: Nil if !isTupleType(in) =>
// A => B => C should be (A => B) => C or A => (B => C)
val in_s = if (isFunctionType(in)) "(" + in + ")" else "" + in
val out_s = if (isFunctionType(out)) "(" + out + ")" else "" + out
@@ -2183,9 +2220,9 @@ trait Types extends api.Types { self: SymbolTable =>
xs.init.mkString("(", ", ", ")") + " => " + xs.last
}
}
- else if (isTupleTypeOrSubtype(this))
- normalize.typeArgs.mkString("(", ", ", if (hasLength(normalize.typeArgs, 1)) ",)" else ")")
- else if (sym.isAliasType && prefixChain.exists(_.termSymbol.isSynthetic) && (normalize ne this))
+ else if (isTupleType(this))
+ targs.mkString("(", ", ", if (hasLength(targs, 1)) ",)" else ")")
+ else if (sym.isAliasType && prefixChain.exists(_.termSymbol.isSynthetic) && (this ne this.normalize))
"" + normalize
else
""
@@ -2220,6 +2257,9 @@ trait Types extends api.Types { self: SymbolTable =>
else {
if (sym.isAliasType) new NoArgsTypeRef(pre, sym) with AliasTypeRef
else if (sym.isAbstractType) new NoArgsTypeRef(pre, sym) with AbstractTypeRef
+ else if (sym.isRefinementClass) new RefinementTypeRef(sym)
+ else if (sym.isPackageClass) new PackageTypeRef(pre, sym)
+ else if (sym.isModuleClass) new ModuleTypeRef(pre, sym)
else new NoArgsTypeRef(pre, sym) with ClassTypeRef
}
})
@@ -2262,7 +2302,7 @@ trait Types extends api.Types { self: SymbolTable =>
override def isTrivial: Boolean = isTrivial0 && (resultType eq resultType.withoutAnnotations)
private lazy val isTrivial0 =
resultType.isTrivial && params.forall{p => p.tpe.isTrivial && (
- /*!settings.YdepMethTpes.value ||*/ !(params.exists(_.tpe.contains(p)) || resultType.contains(p)))
+ !(params.exists(_.tpe.contains(p)) || resultType.contains(p)))
}
def isImplicit = params.nonEmpty && params.head.isImplicit
@@ -2286,8 +2326,9 @@ trait Types extends api.Types { self: SymbolTable =>
}
else existentialAbstraction(params, resultType)
- // implicit args can only be depended on in result type: TODO this may be generalised so that the only constraint is dependencies are acyclic
- def approximate: MethodType = MethodType(params, resultApprox) // if (!settings.YdepMethTpes.value) this else
+ // implicit args can only be depended on in result type:
+ //TODO this may be generalised so that the only constraint is dependencies are acyclic
+ def approximate: MethodType = MethodType(params, resultApprox)
override def finalResultType: Type = resultType.finalResultType
@@ -2616,15 +2657,6 @@ trait Types extends api.Types { self: SymbolTable =>
}
}
- // TODO: I don't really know why this happens -- maybe because
- // the owner hierarchy changes? the other workaround (besides
- // repackExistential) is to explicitly pass expectedTp as the type
- // argument for the call to guard, but repacking the existential
- // somehow feels more robust
- //
- // TODO: check if optimization makes a difference, try something else
- // if necessary (cache?)
-
/** Repack existential types, otherwise they sometimes get unpacked in the
* wrong location (type inference comes up with an unexpected skolem)
*/
@@ -3329,16 +3361,18 @@ trait Types extends api.Types { self: SymbolTable =>
* may or may not be poly? (It filched the standard "canonical creator" name.)
*/
object GenPolyType {
- def apply(tparams: List[Symbol], tpe: Type): Type =
- if (tparams nonEmpty) typeFun(tparams, tpe)
- else tpe // it's okay to be forgiving here
+ def apply(tparams: List[Symbol], tpe: Type): Type = (
+ if (tparams nonEmpty) typeFun(tparams, tpe)
+ else tpe // it's okay to be forgiving here
+ )
def unapply(tpe: Type): Option[(List[Symbol], Type)] = tpe match {
- case PolyType(tparams, restpe) => Some(tparams, restpe)
- case _ => Some(List(), tpe)
+ case PolyType(tparams, restpe) => Some((tparams, restpe))
+ case _ => Some((Nil, tpe))
}
}
+ def genPolyType(params: List[Symbol], tpe: Type): Type = GenPolyType(params, tpe)
- @deprecated("use GenPolyType(...) instead")
+ @deprecated("use genPolyType(...) instead", "2.10.0")
def polyType(params: List[Symbol], tpe: Type): Type = GenPolyType(params, tpe)
/** A creator for anonymous type functions, where the symbol for the type function still needs to be created.
@@ -3615,6 +3649,23 @@ trait Types extends api.Types { self: SymbolTable =>
}
}
+ class TypeUnwrapper(poly: Boolean, existential: Boolean, annotated: Boolean, nullary: Boolean) extends (Type => Type) {
+ def apply(tp: Type): Type = tp match {
+ case AnnotatedType(_, underlying, _) if annotated => apply(underlying)
+ case ExistentialType(_, underlying) if existential => apply(underlying)
+ case PolyType(_, underlying) if poly => apply(underlying)
+ case NullaryMethodType(underlying) if nullary => apply(underlying)
+ case tp => tp
+ }
+ }
+ class ClassUnwrapper(existential: Boolean) extends TypeUnwrapper(poly = true, existential, annotated = true, nullary = false) {
+ override def apply(tp: Type) = super.apply(tp.normalize)
+ }
+
+ object unwrapToClass extends ClassUnwrapper(existential = true) { }
+ object unwrapToStableClass extends ClassUnwrapper(existential = false) { }
+ object unwrapWrapperTypes extends TypeUnwrapper(true, true, true, true) { }
+
trait AnnotationFilter extends TypeMap {
def keepAnnotation(annot: AnnotationInfo): Boolean
@@ -4585,31 +4636,22 @@ trait Types extends api.Types { self: SymbolTable =>
object adaptToNewRunMap extends TypeMap {
private def adaptToNewRun(pre: Type, sym: Symbol): Symbol = {
- if (phase.flatClasses) {
+ if (phase.flatClasses || sym.isRootSymbol || (pre eq NoPrefix) || (pre eq NoType) || sym.isPackageClass)
sym
- } else if (sym == definitions.RootClass) {
- definitions.RootClass
- } else if (sym == definitions.RootPackage) {
- definitions.RootPackage
- } else if (sym.isModuleClass) {
+ else if (sym.isModuleClass) {
val sourceModule1 = adaptToNewRun(pre, sym.sourceModule)
- var result = sourceModule1.moduleClass
- if (result == NoSymbol) result = sourceModule1.initialize.moduleClass
- if (result != NoSymbol) result
- else {
+
+ sourceModule1.moduleClass orElse sourceModule1.initialize.moduleClass orElse {
val msg = "Cannot adapt module class; sym = %s, sourceModule = %s, sourceModule.moduleClass = %s => sourceModule1 = %s, sourceModule1.moduleClass = %s"
debuglog(msg.format(sym, sym.sourceModule, sym.sourceModule.moduleClass, sourceModule1, sourceModule1.moduleClass))
sym
}
- } else if ((pre eq NoPrefix) || (pre eq NoType) || sym.isPackageClass) {
- sym
- } else {
- var rebind0 = pre.findMember(sym.name, BRIDGE, 0, true)
- if (rebind0 == NoSymbol) {
+ }
+ else {
+ var rebind0 = pre.findMember(sym.name, BRIDGE, 0, true) orElse {
if (sym.isAliasType) throw missingAliasException
debugwarn(pre+"."+sym+" does no longer exist, phase = "+phase)
throw new MissingTypeControl // For build manager and presentation compiler purposes
- //assert(false, pre+"."+sym+" does no longer exist, phase = "+phase)
}
/** The two symbols have the same fully qualified name */
def corresponds(sym1: Symbol, sym2: Symbol): Boolean =
@@ -4628,12 +4670,10 @@ trait Types extends api.Types { self: SymbolTable =>
", rebind = " + rebind0.fullLocationString
)
}
- val rebind = rebind0.suchThat(sym => sym.isType || sym.isStable)
- if (rebind == NoSymbol) {
+ rebind0.suchThat(sym => sym.isType || sym.isStable) orElse {
debuglog("" + phase + " " +phase.flatClasses+sym.owner+sym.name+" "+sym.isType)
throw new MalformedType(pre, sym.nameString)
}
- rebind
}
}
def apply(tp: Type): Type = tp match {
@@ -5454,9 +5494,14 @@ trait Types extends api.Types { self: SymbolTable =>
case _: ClassSymbol =>
if (isRaw(sym1, tr1.args))
isSubType(rawToExistential(tp1), tp2, depth)
- else
- sym1.name == tpnme.REFINE_CLASS_NAME &&
+ else if (sym1.isModuleClass) tp2 match {
+ case SingleType(_, sym2) => sym1 == sym2
+ case _ => false
+ }
+ else if (sym1.isRefinementClass)
isSubType(sym1.info, tp2, depth)
+ else false
+
case _: TypeSymbol =>
if (sym1 hasFlag DEFERRED) {
val tp1a = tp1.bounds.hi
diff --git a/src/compiler/scala/reflect/internal/settings/MutableSettings.scala b/src/compiler/scala/reflect/internal/settings/MutableSettings.scala
index 0092f73fe3..b556c33aba 100644
--- a/src/compiler/scala/reflect/internal/settings/MutableSettings.scala
+++ b/src/compiler/scala/reflect/internal/settings/MutableSettings.scala
@@ -43,4 +43,5 @@ abstract class MutableSettings extends AbsSettings {
def Yrecursion: IntSetting
def maxClassfileName: IntSetting
def Xexperimental: BooleanSetting
+ def YvirtPatmat: BooleanSetting
} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/runtime/Settings.scala b/src/compiler/scala/reflect/runtime/Settings.scala
index b4f0123114..27e90c94bd 100644
--- a/src/compiler/scala/reflect/runtime/Settings.scala
+++ b/src/compiler/scala/reflect/runtime/Settings.scala
@@ -23,7 +23,6 @@ class Settings extends internal.settings.MutableSettings {
val overrideObjects = new BooleanSetting(false)
val debug = new BooleanSetting(false)
- // val YdepMethTpes = new BooleanSetting(true)
val Ynotnull = new BooleanSetting(false)
val explaintypes = new BooleanSetting(false)
val verbose = new BooleanSetting(false)
@@ -34,4 +33,6 @@ class Settings extends internal.settings.MutableSettings {
val Yrecursion = new IntSetting(0)
val maxClassfileName = new IntSetting(255)
val Xexperimental = new BooleanSetting(false)
+ val deepCloning = new BooleanSetting (false)
+ val YvirtPatmat = new BooleanSetting(false)
}
diff --git a/src/compiler/scala/reflect/runtime/ToolBoxes.scala b/src/compiler/scala/reflect/runtime/ToolBoxes.scala
index 8cc4d5f788..28f12b378f 100644
--- a/src/compiler/scala/reflect/runtime/ToolBoxes.scala
+++ b/src/compiler/scala/reflect/runtime/ToolBoxes.scala
@@ -1,6 +1,7 @@
package scala.reflect
package runtime
+import scala.tools.nsc
import scala.tools.nsc.reporters.Reporter
import scala.tools.nsc.reporters.StoreReporter
import scala.tools.nsc.reporters.AbstractReporter
@@ -21,8 +22,7 @@ trait ToolBoxes extends { self: Universe =>
class ToolBox(val reporter: Reporter = new StoreReporter, val options: String = "") {
- class ToolBoxGlobal(settings: scala.tools.nsc.Settings, reporter: scala.tools.nsc.reporters.Reporter)
- extends ReflectGlobal(settings, reporter) {
+ class ToolBoxGlobal(settings0: nsc.Settings, reporter0: nsc.reporters.Reporter) extends ReflectGlobal(settings0, reporter0) {
import definitions._
private val trace = scala.tools.nsc.util.trace when settings.debug.value
diff --git a/src/compiler/scala/reflect/runtime/Universe.scala b/src/compiler/scala/reflect/runtime/Universe.scala
index 324fee87ab..7a5dda3d8e 100644
--- a/src/compiler/scala/reflect/runtime/Universe.scala
+++ b/src/compiler/scala/reflect/runtime/Universe.scala
@@ -39,6 +39,11 @@ class Universe extends SymbolTable {
definitions.AnyValClass // force it.
+ type TreeAnnotation = Position
+ val NoTreeAnnotation: TreeAnnotation = NoPosition
+ def positionToAnnotation(pos: Position): TreeAnnotation = pos // TODO
+ def annotationToPosition(annot: TreeAnnotation): Position = annot //TODO
+
// establish root association to avoid cyclic dependency errors later
classToScala(classOf[java.lang.Object]).initialize
diff --git a/src/compiler/scala/tools/ant/ScalaBazaar.scala b/src/compiler/scala/tools/ant/ScalaBazaar.scala
deleted file mode 100644
index fa44715c7f..0000000000
--- a/src/compiler/scala/tools/ant/ScalaBazaar.scala
+++ /dev/null
@@ -1,316 +0,0 @@
-/* __ *\
-** ________ ___ / / ___ Scala Ant Tasks **
-** / __/ __// _ | / / / _ | (c) 2005-2011, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
-
-package scala.tools
-package ant
-
-import scala.collection.DefaultMap
-import scala.collection.{ mutable, immutable }
-
-import java.io.{File, FileInputStream, FileOutputStream, FileWriter, StringReader}
-import java.util.zip.{ZipOutputStream, ZipEntry}
-
-import org.apache.tools.ant.{Project, Task}
-import org.apache.tools.ant.types.{FileSet, Path}
-import org.apache.tools.ant.util.FileUtils
-
-/** A set of files that can be installed at any relative location */
-class LooseFileSet {
- var destination: Option[String] = None
- def setDestination(dest: String) = {
- destination = Some(dest)
- }
-
- var fileset: Option[FileSet] = None
- def addConfiguredFileSet(fs: FileSet) = {
- fileset = Some(fs)
- }
-}
-
-/** An Ant task that generates a Scala Bazaars package (sbp file) along
- * with an advertisement of that package.
- *
- * This task can take the following parameters as attributes:
- * - `file` (mandatory),
- * - `adfile`,
- * - `name` (mandatory),
- * - `version` (mandatory),
- * - `depends`,
- * - `description`,
- * - `link`.
- *
- * @author Gilles Dubochet, Stephane Micheloud
- */
-class ScalaBazaar extends Task with ScalaTask {
-
- /** The unique Ant file utilities instance to use in this task. */
- private val fileUtils = FileUtils.getFileUtils()
-
-/******************************************************************************\
-** Ant user-properties **
-\******************************************************************************/
-
- /** The path to the archive file. */
- private var file: Option[File] = None
- /** The optional path to the advertisement file. */
- private var adfile: Option[File] = None
- /** The name of the package. */
- private var name: Option[String] = None
- /** The version number of the package. */
- private var version: Option[String] = None
- /** An (optional) list of names of the packages it depends of. */
- private var depends: List[String] = Nil
- /** An (optional) description of this package. */
- private var desc: Option[String] = None
- /** An (optional) URL link pointing to the location of the package */
- private var link: Option[String] = None
-
- /** The sets of files to include in the package */
- private object fileSetsMap extends DefaultMap[String, List[FileSet]] {
- private var content = new mutable.HashMap[String, List[FileSet]]()
- def get(key: String): Option[List[FileSet]] = content.get(key)
- override def size: Int = content.size
- def update(key: String, value: FileSet) {
- if (content.contains(key) && content(key) != Nil)
- content.update(key, value :: content(key))
- else content.update(key, List(value))
- }
- def fileSets = content.toList
- def iterator = content.iterator
- }
-
-/******************************************************************************\
-** Internal properties **
-\******************************************************************************/
-
-
-/******************************************************************************\
-** Properties setters **
-\******************************************************************************/
-
- /** Sets the file attribute. Used by [[http://ant.apache.org Ant]].
- * @param input The value of `file`.
- */
- def setFile(input: File) { file = Some(input) }
-
- /** Sets the advertisement file attribute. Used by [[http://ant.apache.org Ant]].
- * @param input The value of `adfile`.
- */
- def setAdfile(input: File) { adfile = Some(input) }
-
- /** Sets the name attribute of this package. Used by [[http://ant.apache.org Ant]].
- * @param input The value of `name`.
- */
- def setName(input: String) { name = Some(input) }
-
- /** Sets the version attribute of this package. Used by [[http://ant.apache.org Ant]].
- * @param input The value of `version`.
- */
- def setVersion(input: String) { version = Some(input) }
-
- /** Sets the depends attribute. Used by [[http://ant.apache.org Ant]].
- * @param input The value for `depends`.
- */
- def setDepends(input: String) = {
- depends = (input split ",").toList.flatMap { s: String =>
- val st = s.trim()
- (if (st != "") List(st) else Nil)
- }
- }
-
- /** Sets the description attribute of this package. Used by [[http://ant.apache.org Ant]].
- * @param input The value of `description`.
- */
- def setDesc(input: String) { desc = Some(input) }
-
- /** Sets the link attribute of this package. Used by [[http://ant.apache.org Ant]].
- * @param input The value of `link`.
- */
- def setLink(input: String) { link = Some(input) }
-
- def addConfiguredLibset(input: FileSet) =
- fileSetsMap.update("lib", input)
-
- def addConfiguredBinset(input: FileSet) =
- fileSetsMap.update("bin", input)
-
- def addConfiguredSrcset(input: FileSet) =
- fileSetsMap.update("src", input)
-
- def addConfiguredManset(input: FileSet) =
- fileSetsMap.update("man", input)
-
- def addConfiguredDocset(input: FileSet) =
- fileSetsMap.update("doc/" + getName, input)
-
- def addConfiguredMiscset(input: FileSet) =
- fileSetsMap.update("misc/" + getName, input)
-
- def addConfiguredLooseset(set: LooseFileSet) = {
- (set.destination, set.fileset) match {
- case (None, _) =>
- buildError("destination not specified for a loose file set")
-
- case (_, None) =>
- buildError("no files specified for a loose file set")
-
- case (Some(dest), Some(fileset)) =>
- fileSetsMap.update(dest, fileset)
- }
- }
-
-/******************************************************************************\
-** Properties getters **
-\******************************************************************************/
-
- /** Gets the value of the file attribute in a Scala-friendly form.
- * @return The file as a file.
- */
- private def getName: String =
- if (name.isEmpty) buildError("Name attribute must be defined first.")
- else name.get
-
- /** Gets the value of the file attribute in a Scala-friendly form.
- * @return The file as a file.
- */
- private def getFile: File =
- if (file.isEmpty) buildError("Member 'file' is empty.")
- else getProject resolveFile file.get.toString
-
- /** Gets the value of the adfile attribute in a Scala-friendly form.
- * @return The adfile as a file.
- */
- private def getAdfile: File =
- if (adfile.isEmpty) buildError("Member 'adfile' is empty.")
- else getProject resolveFile adfile.get.toString
-
-/******************************************************************************\
-** Compilation and support methods **
-\******************************************************************************/
-
- /** Transforms a string name into a file relative to the provided base
- * directory.
- * @param base A file pointing to the location relative to which the name
- * will be resolved.
- * @param name A relative or absolute path to the file as a string.
- * @return A file created from the name and the base file.
- */
- private def nameToFile(base: File)(name: String): File =
- existing(fileUtils.resolveFile(base, name))
-
- /** Transforms a string name into a file relative to the build advertDoc
- * directory.
- * @param name A relative or absolute path to the file as a string.
- * @return A file created from the name.
- */
- private def nameToFile(name: String): File =
- existing(getProject resolveFile name)
-
- /** Tests if a file exists and prints a warning in case it doesn't.
- * Always returns the file, even if it doesn't exist.
- * @param file A file to test for existance.
- * @return The same file.
- */
- private def existing(file: File): File = {
- if (!file.exists)
- log("Element '" + file.toString + "' does not exist.", Project.MSG_WARN)
- file
- }
-
- private def writeFile(file: File, content: String) {
- if (file.exists && !file.canWrite)
- buildError("File " + file + " is not writable")
- else {
- val writer = new FileWriter(file, false)
- writer write content
- writer.close()
- }
- }
-
-/******************************************************************************\
-** The big execute method **
-\******************************************************************************/
-
- /** Performs the compilation. */
- override def execute() {
- // Tests if all mandatory attributes are set and valid.
- if (file.isEmpty) buildError("Attribute 'file' is not set.")
- if (name.isEmpty) buildError("Attribute 'name' is not set.")
- if (version.isEmpty) buildError("Attribute 'version' is not set.")
-
- val pack = {
- <package>
- <name>{name.get}</name>
- <version>{version.get}</version>{
- if (!depends.isEmpty)
- <depends>{
- for (depend <- depends) yield
- <name>{depend}</name>
- }</depends>
- else Nil
- }{
- if (!desc.isEmpty)
- <description>{desc.get}</description>
- else Nil
- }
- </package>
- }
-
- log("Creating package '" + name.get + "'")
-
- // Creates the advert file
- val advert = {
- <availablePackage>
- {pack}
- {link match {
- case None => <link>INSERT LINK HERE</link>
- case Some(str) => <link>{str}</link>
- }}
- </availablePackage>
- }
-
- if (!adfile.isEmpty)
- writeFile(getAdfile, advert.toString)
-
- // Checks for new files and creates the ZIP
-
- val zipContent =
- for {
- (folder, fileSets) <- fileSetsMap.fileSets
- fileSet <- fileSets
- file <- fileSet.getDirectoryScanner(getProject).getIncludedFiles.toList
- } yield Triple(folder, fileSet.getDir(getProject), file)
- val zip = new ZipOutputStream(new FileOutputStream(file.get, false))
- if (!zipContent.isEmpty) {
- for (Triple(destFolder, srcFolder, file) <- zipContent) {
- log(file, Project.MSG_DEBUG)
- zip putNextEntry new ZipEntry(destFolder + "/" + file)
- val input = new FileInputStream(nameToFile(srcFolder)(file))
- val buf = new Array[Byte](10240)
- var n = input.read(buf, 0, buf.length)
- while (n >= 0) {
- zip.write (buf, 0, n)
- n = input.read(buf, 0, buf.length)
- }
- zip.closeEntry()
- input.close()
- }
- } else log("Archive contains no files.", Project.MSG_VERBOSE)
- zip putNextEntry new ZipEntry("meta/description")
- val packInput = new StringReader(pack.toString)
- var byte = packInput.read()
- while (byte != -1) {
- zip.write (byte)
- byte = packInput.read()
- }
- zip.closeEntry()
- packInput.close()
- zip.close()
- }
-
-}
diff --git a/src/compiler/scala/tools/ant/ScalaTool.scala b/src/compiler/scala/tools/ant/ScalaTool.scala
index 35e26bd9f5..3fdbcd1140 100644
--- a/src/compiler/scala/tools/ant/ScalaTool.scala
+++ b/src/compiler/scala/tools/ant/ScalaTool.scala
@@ -125,8 +125,7 @@ class ScalaTool extends ScalaMatchingTask {
* Adds an Ant Path reference to the tool's classpath.
* Note that all entries in the path must exist either relative to the project
* basedir or with an absolute path to a file in the filesystem. As a result,
- * this is not a mechanism for setting the classpath for more general use scripts,
- * such as those distributed within sbaz distribution packages.
+ * this is not a mechanism for setting the classpath for more general use scripts.
*/
def setClassPathRef(input: Reference) {
val tmpPath = emptyPath
diff --git a/src/compiler/scala/tools/ant/antlib.xml b/src/compiler/scala/tools/ant/antlib.xml
index bbdf1fc9db..78159e6d10 100644
--- a/src/compiler/scala/tools/ant/antlib.xml
+++ b/src/compiler/scala/tools/ant/antlib.xml
@@ -1,6 +1,4 @@
<antlib>
- <!--<taskdef name="scala"
- classname="scala.tools.ant.Scala"/>-->
<taskdef name="classloadVerify"
classname="scala.tools.ant.ClassloadVerify"/>
<taskdef name="fsc"
@@ -9,16 +7,12 @@
classname="scala.tools.ant.Scalac"/>
<taskdef name="scalascript"
classname="scala.tools.ant.ScalaTool"/>
- <taskdef name="sbaz"
- classname="scala.tools.ant.ScalaBazaar"/>
<taskdef name="scaladoc"
classname="scala.tools.ant.Scaladoc"/>
<taskdef name="scalatool"
classname="scala.tools.ant.ScalaTool"/>
<taskdef name="same"
classname="scala.tools.ant.Same"/>
- <!--<taskdef name="scalatest"
- classname="scala.tools.ant.ScalaDoc"/>-->
<taskdef name="pack200"
classname="scala.tools.ant.Pack200Task"/>
</antlib>
diff --git a/src/compiler/scala/tools/cmd/FromString.scala b/src/compiler/scala/tools/cmd/FromString.scala
index e4504702d4..3792c26c34 100644
--- a/src/compiler/scala/tools/cmd/FromString.scala
+++ b/src/compiler/scala/tools/cmd/FromString.scala
@@ -14,9 +14,9 @@ import scala.reflect.OptManifest
* example instances are in the companion object, but in general
* either IntFromString will suffice or you'll want custom transformers.
*/
-abstract class FromString[+T](implicit m: OptManifest[T]) extends scala.runtime.AbstractPartialFunction[String, T] {
+abstract class FromString[+T](implicit m: OptManifest[T]) extends PartialFunction[String, T] {
def apply(s: String): T
- def _isDefinedAt(s: String): Boolean = true
+ def isDefinedAt(s: String): Boolean = true
def zero: T = apply("")
def targetString: String = m.toString
@@ -30,20 +30,20 @@ object FromString {
/** Path related stringifiers.
*/
val ExistingFile: FromString[File] = new FromString[File] {
- override def _isDefinedAt(s: String) = toFile(s).isFile
+ override def isDefinedAt(s: String) = toFile(s).isFile
def apply(s: String): File =
if (isDefinedAt(s)) toFile(s)
else cmd.runAndExit(println("'%s' is not an existing file." format s))
}
val ExistingDir: FromString[Directory] = new FromString[Directory] {
- override def _isDefinedAt(s: String) = toDir(s).isDirectory
+ override def isDefinedAt(s: String) = toDir(s).isDirectory
def apply(s: String): Directory =
if (isDefinedAt(s)) toDir(s)
else cmd.runAndExit(println("'%s' is not an existing directory." format s))
}
def ExistingDirRelativeTo(root: Directory) = new FromString[Directory] {
private def resolve(s: String) = toDir(s) toAbsoluteWithRoot root toDirectory
- override def _isDefinedAt(s: String) = resolve(s).isDirectory
+ override def isDefinedAt(s: String) = resolve(s).isDirectory
def apply(s: String): Directory =
if (isDefinedAt(s)) resolve(s)
else cmd.runAndExit(println("'%s' is not an existing directory." format resolve(s)))
@@ -65,7 +65,7 @@ object FromString {
/** Implicit as the most likely to be useful as-is.
*/
implicit val IntFromString: FromString[Int] = new FromString[Int] {
- override def _isDefinedAt(s: String) = safeToInt(s).isDefined
+ override def isDefinedAt(s: String) = safeToInt(s).isDefined
def apply(s: String) = safeToInt(s).get
def safeToInt(s: String): Option[Int] = try Some(java.lang.Integer.parseInt(s)) catch { case _: NumberFormatException => None }
}
diff --git a/src/compiler/scala/tools/nsc/ast/DocComments.scala b/src/compiler/scala/tools/nsc/ast/DocComments.scala
index 678f7b3028..d3f4688d4b 100755
--- a/src/compiler/scala/tools/nsc/ast/DocComments.scala
+++ b/src/compiler/scala/tools/nsc/ast/DocComments.scala
@@ -229,31 +229,36 @@ trait DocComments { self: Global =>
* 1. It takes longer to run compared to merge
* 2. The inheritdoc annotation should not be used very often, as building the comment from pieces severely
* impacts performance
+ *
+ * @param parent The source (or parent) comment
+ * @param child The child (overriding member or usecase) comment
+ * @param sym The child symbol
+ * @return The child comment with the inheritdoc sections expanded
*/
- def expandInheritdoc(src: String, dst: String, sym: Symbol): String =
- if (dst.indexOf("@inheritdoc") == -1)
- dst
+ def expandInheritdoc(parent: String, child: String, sym: Symbol): String =
+ if (child.indexOf("@inheritdoc") == -1)
+ child
else {
- val srcSections = tagIndex(src)
- val dstSections = tagIndex(dst)
- val srcTagMap = sectionTagMap(src, srcSections)
- val srcNamedParams = Map() +
- ("@param" -> paramDocs(src, "@param", srcSections)) +
- ("@tparam" -> paramDocs(src, "@tparam", srcSections)) +
- ("@throws" -> paramDocs(src, "@throws", srcSections))
+ val parentSections = tagIndex(parent)
+ val childSections = tagIndex(child)
+ val parentTagMap = sectionTagMap(parent, parentSections)
+ val parentNamedParams = Map() +
+ ("@param" -> paramDocs(parent, "@param", parentSections)) +
+ ("@tparam" -> paramDocs(parent, "@tparam", parentSections)) +
+ ("@throws" -> paramDocs(parent, "@throws", parentSections))
val out = new StringBuilder
- def replaceInheritdoc(src: String, dst: String) =
- if (dst.indexOf("@inheritdoc") == -1)
- dst
- else
- dst.replaceAllLiterally("@inheritdoc", src)
+ def replaceInheritdoc(childSection: String, parentSection: => String) =
+ if (childSection.indexOf("@inheritdoc") == -1)
+ childSection
+ else
+ childSection.replaceAllLiterally("@inheritdoc", parentSection)
- def getSourceSection(section: (Int, Int)): String = {
+ def getParentSection(section: (Int, Int)): String = {
- def getSectionHeader = extractSectionTag(dst, section) match {
- case param@("@param"|"@tparam"|"@throws") => param + " " + extractSectionParam(dst, section)
+ def getSectionHeader = extractSectionTag(child, section) match {
+ case param@("@param"|"@tparam"|"@throws") => param + " " + extractSectionParam(child, section)
case other => other
}
@@ -261,17 +266,19 @@ trait DocComments { self: Global =>
paramMap.get(param) match {
case Some(section) =>
// Cleanup the section tag and parameter
- val sectionTextBounds = extractSectionText(src, section)
- cleanupSectionText(src.substring(sectionTextBounds._1, sectionTextBounds._2))
+ val sectionTextBounds = extractSectionText(parent, section)
+ cleanupSectionText(parent.substring(sectionTextBounds._1, sectionTextBounds._2))
case None =>
reporter.info(sym.pos, "The \"" + getSectionHeader + "\" annotation of the " + sym +
" comment contains @inheritdoc, but the corresponding section in the parent is not defined.", true)
"<invalid inheritdoc annotation>"
}
- dst.substring(section._1, section._1 + 7) match {
- case param@("@param "|"@tparam"|"@throws") => sectionString(extractSectionParam(dst, section), srcNamedParams(param.trim))
- case _ => sectionString(extractSectionTag(dst, section), srcTagMap)
+ child.substring(section._1, section._1 + 7) match {
+ case param@("@param "|"@tparam"|"@throws") =>
+ sectionString(extractSectionParam(child, section), parentNamedParams(param.trim))
+ case _ =>
+ sectionString(extractSectionTag(child, section), parentTagMap)
}
}
@@ -283,11 +290,11 @@ trait DocComments { self: Global =>
// Append main comment
out.append("/**")
- out.append(replaceInheritdoc(mainComment(src, srcSections), mainComment(dst, dstSections)))
+ out.append(replaceInheritdoc(mainComment(child, childSections), mainComment(parent, parentSections)))
// Append sections
- for (section <- dstSections)
- out.append(replaceInheritdoc(getSourceSection(section), dst.substring(section._1, section._2)))
+ for (section <- childSections)
+ out.append(replaceInheritdoc(child.substring(section._1, section._2), getParentSection(section)))
out.append("*/")
out.toString
diff --git a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala
index 9466d1c1f2..acbdcd501f 100644
--- a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala
+++ b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala
@@ -9,14 +9,13 @@ package ast
import compat.Platform.EOL
import symtab.Flags._
-/** The object <code>nodePrinter</code> converts the internal tree
- * representation to a string formatted as a Scala expression.
+/** The object `nodePrinter` converts the internal tree
+ * representation to a string.
*
* @author Stephane Micheloud
- * @version 1.0
+ * @author Paul Phillips
*/
abstract class NodePrinters {
-
val global: Global
import global._
@@ -25,262 +24,332 @@ abstract class NodePrinters {
}
var infolevel = InfoLevel.Quiet
- object nodeToString extends Function1[Tree, String] {
+ def nodeToString: Tree => String =
+ if (sys.props contains "scala.colors") nodeToColorizedString
+ else nodeToRegularString
+
+ object nodeToRegularString extends DefaultPrintAST with (Tree => String) {
+ def apply(tree: Tree) = stringify(tree)
+ }
+
+ object nodeToColorizedString extends ColorPrintAST with (Tree => String) {
+ def apply(tree: Tree) = stringify(tree)
+ }
+
+ trait ColorPrintAST extends DefaultPrintAST {
+ import scala.tools.util.color._
+
+ def keywordColor = Cyan
+ def typeColor = Yellow
+ def termColor = Blue
+ def flagColor = Red
+ def literalColor = Green
+
+ override def showFlags(tree: MemberDef) =
+ super.showFlags(tree) in flagColor.bright
+
+ override def showDefTreeName(tree: DefTree) =
+ if (tree.name.isTermName) tree.name.decode in termColor.bright
+ else tree.name.decode in typeColor.bright
+
+ override def showName(name: Name) =
+ if (name == nme.EMPTY || name == tpnme.EMPTY) "<empty>" in keywordColor
+ else if (name.isTermName) name.decode in termColor
+ else name.decode in typeColor
+
+ override def showLiteral(lit: Literal) =
+ super.showLiteral(lit) in literalColor.bright
+ }
+
+ trait DefaultPrintAST extends PrintAST {
+ def showDefTreeName(tree: DefTree) = showName(tree.name)
+ def showFlags(tree: MemberDef) = flagsToString(tree.symbol.flags | tree.mods.flags)
+ def showLiteral(lit: Literal) = lit.value.escapedStringValue
+ def showTypeTree(tt: TypeTree) = "<tpt>" + emptyOrComment(showType(tt))
+ def showName(name: Name) = name match {
+ case nme.EMPTY | tpnme.EMPTY => "<empty>"
+ case name => "\"" + name + "\""
+ }
+
+ def showSymbol(tree: Tree): String = {
+ val sym = tree.symbol
+ if (sym == null || sym == NoSymbol) ""
+ else sym.defString + sym.locationString
+ }
+ def showType(tree: Tree): String = {
+ val tpe = tree.tpe
+ if (tpe == null || tpe == NoType) ""
+ else "tree.tpe=" + tpe
+ }
+
+ def showAttributes(tree: Tree): String = {
+ if (infolevel == InfoLevel.Quiet) ""
+ else {
+ try { List(showSymbol(tree), showType(tree)) filterNot (_ == "") mkString ", " trim }
+ catch { case ex: Throwable => "sym= <error> " + ex.getMessage }
+ }
+ }
+ }
+
+ trait PrintAST {
private val buf = new StringBuilder
+ private var level = 0
- def apply(tree: Tree): String = {
- def traverse(tree: Tree, level: Int, comma: Boolean) {
- def println(s: String) {
- for (i <- 0 until level) buf.append(" ")
- buf.append(s)
- buf.append(EOL)
- }
- def printcln(s: String) {
- for (i <- 0 until level) buf.append(" ")
- buf.append(s)
- if (comma) buf.append(",")
- buf.append(EOL)
- }
- def annotationInfoToString(annot: AnnotationInfo): String = {
- val str = new StringBuilder
- str.append(annot.atp.toString())
- if (!annot.args.isEmpty)
- str.append(annot.args.mkString("(", ",", ")"))
- if (!annot.assocs.isEmpty)
- for (((name, value), index) <- annot.assocs.zipWithIndex) {
- if (index > 0)
- str.append(", ")
- str.append(name).append(" = ").append(value)
- }
- str.toString
- }
- def symflags(tree: Tree): String = {
- val buf = new StringBuffer
- val sym = tree.symbol
- buf append flagsToString(sym.flags)
+ def showName(name: Name): String
+ def showDefTreeName(defTree: DefTree): String
+ def showFlags(tree: MemberDef): String
+ def showLiteral(lit: Literal): String
+ def showTypeTree(tt: TypeTree): String
+ def showAttributes(tree: Tree): String // symbol and type
+
+ def showRefTreeName(tree: Tree): String = tree match {
+ case SelectFromTypeTree(qual, name) => showRefTreeName(qual) + "#" + showName(name)
+ case Select(qual, name) => showRefTreeName(qual) + "." + showName(name)
+ case Ident(name) => showName(name)
+ case _ => "" + tree
+ }
+ def showRefTree(tree: RefTree): String = {
+ def prefix0 = showRefTreeName(tree.qualifier)
+ def prefix = if (prefix0 == "") "" else (tree match {
+ case SelectFromTypeTree(_, _) => prefix0 + "#"
+ case Select(_, _) => prefix0 + "."
+ case _ => ""
+ })
+ prefix + showName(tree.name) + emptyOrComment(showAttributes(tree))
+ }
- val annots = ", annots=" + (
- if (!sym.annotations.isEmpty)
- sym.annotations.map(annotationInfoToString).mkString("[", ",", "]")
- else
- tree.asInstanceOf[MemberDef].mods.annotations)
- (if (buf.length() > 2) buf.substring(3)
- else "0") + ", // flags=" + flagsToString(sym.flags) + annots
- }
+ def emptyOrComment(s: String) = if (s == "") "" else " // " + s
- def nodeinfo(tree: Tree): String =
- if (infolevel == InfoLevel.Quiet) ""
- else {
- try {
- val buf = new StringBuilder(" // sym=" + tree.symbol)
- if (tree.hasSymbol) {
- if (tree.symbol.isPrimaryConstructor)
- buf.append(", isPrimaryConstructor")
- else if (tree.symbol.isConstructor)
- buf.append(", isConstructor")
- if (tree.symbol != NoSymbol)
- buf.append(", sym.owner=" + tree.symbol.owner)
- buf.append(", sym.tpe=" + tree.symbol.tpe)
- }
- buf.append(", tpe=" + tree.tpe)
- if (tree.tpe != null) {
- var sym = tree.tpe.termSymbol
- if (sym == NoSymbol) sym = tree.tpe.typeSymbol
- buf.append(", tpe.sym=" + sym)
- if (sym != NoSymbol) {
- buf.append(", tpe.sym.owner=" + sym.owner)
- if ((infolevel > InfoLevel.Normal) &&
- !(sym.owner eq definitions.ScalaPackageClass) &&
- !sym.isModuleClass && !sym.isPackageClass &&
- !sym.isJavaDefined) {
- val members = for (m <- tree.tpe.decls)
- yield m.toString() + ": " + m.tpe + ", "
- buf.append(", tpe.decls=" + members)
- }
- }
- }
- buf.toString
- } catch {
- case ex: Throwable =>
- return " // sym= <error> " + ex.getMessage
- }
- }
- def nodeinfo2(tree: Tree): String =
- (if (comma) "," else "") + nodeinfo(tree)
+ def stringify(tree: Tree): String = {
+ buf.clear()
+ level = 0
+ traverse(tree)
+ buf.toString
+ }
+ def traverseAny(x: Any) {
+ x match {
+ case t: Tree => traverse(t)
+ case xs: List[_] => printMultiline("List", "")(xs foreach traverseAny)
+ case _ => println("" + x)
+ }
+ }
+ def println(s: String) = printLine(s, "")
+
+ def printLine(value: String, comment: String) {
+ buf append " " * level
+ buf append value
+ if (comment != "") {
+ if (value != "")
+ buf append " "
- def applyCommon(name: String, tree: Tree, fun: Tree, args: List[Tree]) {
- println(name + "(" + nodeinfo(tree))
- traverse(fun, level + 1, true)
- if (args.isEmpty)
- println(" Nil // no argument")
- else {
- val n = args.length
- println(" List( // " + n + " arguments(s)")
- for (i <- 0 until n)
- traverse(args(i), level + 2, i < n-1)
- println(" )")
- }
- printcln(")")
+ buf append "// "
+ buf append comment
+ }
+ buf append EOL
+ }
+
+ def annotationInfoToString(annot: AnnotationInfo): String = {
+ val str = new StringBuilder
+ str.append(annot.atp.toString())
+ if (!annot.args.isEmpty)
+ str.append(annot.args.mkString("(", ",", ")"))
+ if (!annot.assocs.isEmpty)
+ for (((name, value), index) <- annot.assocs.zipWithIndex) {
+ if (index > 0)
+ str.append(", ")
+ str.append(name).append(" = ").append(value)
}
+ str.toString
+ }
+ def printModifiers(tree: MemberDef) {
+ val annots0 = tree.symbol.annotations match {
+ case Nil => tree.mods.annotations
+ case xs => xs map annotationInfoToString
+ }
+ val annots = annots0 match {
+ case Nil => ""
+ case xs => " " + xs.mkString("@{ ", ", ", " }")
+ }
+ val flagString = showFlags(tree) match {
+ case "" => "0"
+ case s => s
+ }
+ println(flagString + annots)
+ }
+
+ def applyCommon(tree: Tree, fun: Tree, args: List[Tree]) {
+ printMultiline(tree) {
+ traverse(fun)
+ traverseList("Nil", "argument")(args)
+ }
+ }
+
+ def printMultiline(tree: Tree)(body: => Unit) {
+ printMultiline(tree.printingPrefix, showAttributes(tree))(body)
+ }
+ def printMultiline(prefix: String, comment: String)(body: => Unit) {
+ printLine(prefix + "(", comment)
+ indent(body)
+ println(")")
+ }
- tree match {
- case AppliedTypeTree(tpt, args) => applyCommon("AppliedTypeTree", tree, tpt, args)
- case Apply(fun, args) => applyCommon("Apply", tree, fun, args)
- case ApplyDynamic(fun, args) => applyCommon("ApplyDynamic", tree, fun, args)
+ @inline private def indent[T](body: => T): T = {
+ level += 1
+ try body
+ finally level -= 1
+ }
- case Block(stats, expr) =>
- println("Block(" + nodeinfo(tree))
- if (stats.isEmpty)
- println(" List(), // no statement")
- else {
- val n = stats.length
- println(" List( // " + n + " statement(s)")
- for (i <- 0 until n)
- traverse(stats(i), level + 2, i < n-1)
- println(" ),")
- }
- traverse(expr, level + 1, false)
- printcln(")")
- case ClassDef(mods, name, tparams, impl) =>
- println("ClassDef(" + nodeinfo(tree))
- println(" " + symflags(tree))
- println(" \"" + name + "\",")
- if (tparams.isEmpty)
- println(" List(), // no type parameter")
- else {
- val n = tparams.length
- println(" List( // " + n + " type parameter(s)")
- for (i <- 0 until n)
- traverse(tparams(i), level + 2, i < n-1)
- println(" ),")
- }
- traverse(impl, level + 1, false)
- printcln(")")
- case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
- println("DefDef(" + nodeinfo(tree))
- println(" " + symflags(tree))
- println(" \"" + name + "\",")
- if (tparams.isEmpty)
- println(" List(), // no type parameter")
- else {
- val n = tparams.length
- println(" List( // " + n + " type parameter(s)")
- for (i <- 0 until n)
- traverse(tparams(i), level + 2, i < n-1)
- println(" ),")
+ def traverseList(ifEmpty: String, what: String)(trees: List[Tree]) {
+ if (trees.isEmpty)
+ println(ifEmpty)
+ else if (trees.tail.isEmpty)
+ traverse(trees.head)
+ else {
+ printLine("", trees.length + " " + what + "s")
+ trees foreach traverse
+ }
+ }
+
+ def printSingle(tree: Tree, name: Name) {
+ println(tree.printingPrefix + "(" + showName(name) + ")" + showAttributes(tree))
+ }
+
+ def traverse(tree: Tree) {
+ tree match {
+ case AppliedTypeTree(tpt, args) => applyCommon(tree, tpt, args)
+ case ApplyDynamic(fun, args) => applyCommon(tree, fun, args)
+ case Apply(fun, args) => applyCommon(tree, fun, args)
+
+ case Throw(Ident(name)) =>
+ printSingle(tree, name)
+
+ case Function(vparams, body) =>
+ printMultiline(tree) {
+ traverseList("()", "parameter")(vparams)
+ traverse(body)
+ }
+ case Try(block, catches, finalizer) =>
+ printMultiline(tree) {
+ traverse(block)
+ traverseList("{}", "case")(catches)
+ if (finalizer ne EmptyTree)
+ traverse(finalizer)
+ }
+
+ case Match(selector, cases) =>
+ printMultiline(tree) {
+ traverse(selector)
+ traverseList("", "case")(cases)
+ }
+ case CaseDef(pat, guard, body) =>
+ printMultiline(tree) {
+ traverse(pat)
+ if (guard ne EmptyTree)
+ traverse(guard)
+ traverse(body)
+ }
+ case Block(stats, expr) =>
+ printMultiline(tree) {
+ traverseList("{}", "statement")(stats)
+ traverse(expr)
+ }
+ case cd @ ClassDef(mods, name, tparams, impl) =>
+ printMultiline(tree) {
+ printModifiers(cd)
+ println(showDefTreeName(cd))
+ traverseList("[]", "type parameter")(tparams)
+ traverse(impl)
+ }
+ case md @ ModuleDef(mods, name, impl) =>
+ printMultiline(tree) {
+ printModifiers(md)
+ println(showDefTreeName(md))
+ traverse(impl)
+ }
+ case dd @ DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
+ printMultiline(tree) {
+ printModifiers(dd)
+ println(showDefTreeName(dd))
+ traverseList("[]", "type parameter")(tparams)
+ vparamss match {
+ case Nil => println("Nil")
+ case Nil :: Nil => println("List(Nil)")
+ case ps :: Nil =>
+ printLine("", "1 parameter list")
+ ps foreach traverse
+ case pss =>
+ printLine("", pss.length + " parameter lists")
+ pss foreach (ps => traverseList("()", "parameter")(ps))
}
- val n = vparamss.length
- if (n == 1 && vparamss(0).isEmpty)
- println(" List(List()), // no parameter")
- else {
- println(" List(")
- for (i <- 0 until n) {
- val m = vparamss(i).length
- println(" List( // " + m + " parameter(s)")
- for (j <- 0 until m)
- traverse(vparamss(i)(j), level + 3, j < m-1)
- println(" )")
+ traverse(tpt)
+ traverse(rhs)
+ }
+ case EmptyTree =>
+ println(showName(nme.EMPTY))
+ case lit @ Literal(value) =>
+ println(showLiteral(lit))
+ case New(tpt) =>
+ printMultiline(tree)(traverse(tpt))
+ case Super(This(qual), mix) =>
+ println("Super(This(" + showName(qual) + "), " + showName(mix) + ")")
+ case Super(qual, mix) =>
+ printMultiline(tree) {
+ traverse(qual)
+ showName(mix)
+ }
+ case Template(parents, self, body) =>
+ printMultiline(tree) {
+ val ps0 = parents map { p =>
+ if (p.tpe eq null) p match {
+ case x: RefTree => showRefTree(x)
+ case x => "" + x
}
- println(" ),")
- }
- println(" " + tpt + ",")
- traverse(rhs, level + 1, false)
- printcln(")")
- case EmptyTree =>
- printcln("EmptyTree")
- case Ident(name) =>
- printcln("Ident(\"" + name + "\")" + nodeinfo2(tree))
- case Literal(value) =>
- printcln("Literal(" + value + ")")
- case New(tpt) =>
- println("New(" + nodeinfo(tree))
- traverse(tpt, level + 1, false)
- printcln(")")
- case Select(qualifier, selector) =>
- println("Select(" + nodeinfo(tree))
- traverse(qualifier, level + 1, true)
- printcln(" \"" + selector + "\")")
- case Super(qual, mix) =>
- println("Super(\"" + mix + "\")" + nodeinfo(tree))
- traverse(qual, level + 1, true)
- case Template(parents, self, body) =>
- println("Template(" + nodeinfo(tree))
- println(" " + parents.map(p =>
- if (p.tpe ne null) p.tpe.typeSymbol else "null-" + p
- ) + ", // parents")
- traverse(self, level + 1, true)
- if (body.isEmpty)
- println(" List() // no body")
- else {
- val n = body.length
- println(" List( // body")
- for (i <- 0 until n)
- traverse(body(i), level + 2, i < n-1)
- println(" )")
- }
- printcln(")")
- case This(qual) =>
- println("This(\"" + qual + "\")" + nodeinfo2(tree))
- case TypeApply(fun, args) =>
- println("TypeApply(" + nodeinfo(tree))
- traverse(fun, level + 1, true)
- if (args.isEmpty)
- println(" List() // no argument")
- else {
- val n = args.length
- println(" List(")
- for (i <- 0 until n)
- traverse(args(i), level + 1, i < n-1)
- println(" )")
+ else showName(newTypeName(p.tpe.typeSymbol.fullName))
}
- printcln(")")
- case TypeTree() =>
- printcln("TypeTree()" + nodeinfo2(tree))
- case Typed(expr, tpt) =>
- println("Typed(" + nodeinfo(tree))
- traverse(expr, level + 1, true)
- traverse(tpt, level + 1, false)
- printcln(")")
- case ValDef(mods, name, tpt, rhs) =>
- println("ValDef(" + nodeinfo(tree))
- println(" " + symflags(tree))
- println(" \"" + name + "\",")
- traverse(tpt, level + 1, true)
- traverse(rhs, level + 1, false)
- printcln(")")
- case PackageDef(pid, stats) =>
- println("PackageDef(")
- traverse(pid, level + 1, false)
- println(",\n")
- for (stat <- stats)
- traverse(stat, level + 1, false)
- printcln(")")
- case _ =>
- tree match {
- case p: Product =>
- if (p.productArity != 0) {
- println(p.productPrefix+"(")
- for (elem <- (0 until p.productArity) map p.productElement) {
- def printElem(elem: Any, level: Int): Unit = elem match {
- case t: Tree =>
- traverse(t, level, false)
- case xs: List[_] =>
- print("List(")
- for (x <- xs) printElem(x, level+1)
- printcln(")")
- case _ =>
- println(elem.toString)
- }
- printElem(elem, level+1)
- }
- printcln(")")
- } else printcln(p.productPrefix)
- }
- }
+ printLine(ps0 mkString ", ", "parents")
+ traverse(self)
+ traverseList("{}", "statement")(body)
+ }
+ case This(qual) =>
+ printSingle(tree, qual)
+ case TypeApply(fun, args) =>
+ printMultiline(tree) {
+ traverse(fun)
+ traverseList("[]", "type argument")(args)
+ }
+ case tt @ TypeTree() =>
+ println(showTypeTree(tt))
+
+ case Typed(expr, tpt) =>
+ printMultiline(tree) {
+ traverse(expr)
+ traverse(tpt)
+ }
+ case vd @ ValDef(mods, name, tpt, rhs) =>
+ printMultiline(tree) {
+ printModifiers(vd)
+ println(showDefTreeName(vd))
+ traverse(tpt)
+ traverse(rhs)
+ }
+ case td @ TypeDef(mods, name, tparams, rhs) =>
+ printMultiline(tree) {
+ printModifiers(td)
+ println(showDefTreeName(td))
+ traverseList("[]", "type parameter")(tparams)
+ traverse(rhs)
+ }
+
+ case PackageDef(pid, stats) =>
+ printMultiline("PackageDef", "")(pid :: stats foreach traverse)
+
+ case _ =>
+ tree match {
+ case t: RefTree => println(showRefTree(t))
+ case t if t.productArity == 0 => println(tree.printingPrefix)
+ case t => printMultiline(tree)(tree.productIterator foreach traverseAny)
+ }
}
- buf setLength 0
- traverse(tree, 0, false)
- buf.toString
}
}
diff --git a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala
index c1d6c1a4d4..3302c11127 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala
@@ -352,144 +352,17 @@ abstract class TreeBrowsers {
* Tree.
*/
object TreeInfo {
-
/** Return the case class name and the Name, if the node defines one */
- def treeName(t: Tree): (String, Name) = t match {
- case ProgramTree(units) =>
- ("Program", EMPTY)
-
- case UnitTree(unit) =>
- ("CompilationUnit", newTermName("" + unit))
-
- case DocDef(comment, definition) =>
- ("DocDef", EMPTY)
-
- case ClassDef(mods, name, tparams, impl) =>
- ("ClassDef", name)
-
- case PackageDef(packaged, impl) =>
- ("PackageDef", EMPTY)
-
- case ModuleDef(mods, name, impl) =>
- ("ModuleDef", name)
-
- case ValDef(mods, name, tpe, rhs) =>
- ("ValDef", name)
-
- case DefDef(mods, name, tparams, vparams, tpe, rhs) =>
- ("DefDef", name)
-
- case TypeDef(mods, name, tparams, rhs) =>
- ("TypeDef", name)
-
- case Import(expr, selectors) =>
- ("Import", EMPTY)
-
- case CaseDef(pat, guard, body) =>
- ("CaseDef", EMPTY)
-
- case Template(parents, self, body) =>
- ("Template", EMPTY)
-
- case LabelDef(name, params, rhs) =>
- ("LabelDef", name)
-
- case Block(stats, expr) =>
- ("Block", EMPTY)
-
- case Alternative(trees) =>
- ("Alternative", EMPTY)
-
- case Bind(name, rhs) =>
- ("Bind", name)
-
- case UnApply(fun, args) =>
- ("UnApply", EMPTY)
-
- case Match(selector, cases) =>
- ("Visitor", EMPTY)
-
- case Function(vparams, body) =>
- ("Function", EMPTY)
-
- case Assign(lhs, rhs) =>
- ("Assign", EMPTY)
-
- case If(cond, thenp, elsep) =>
- ("If", EMPTY)
-
- case Return(expr) =>
- ("Return", EMPTY)
-
- case Throw(expr) =>
- ("Throw", EMPTY)
-
- case New(init) =>
- ("New", EMPTY)
-
- case Typed(expr, tpe) =>
- ("Typed", EMPTY)
-
- case TypeApply(fun, args) =>
- ("TypeApply", EMPTY)
-
- case Apply(fun, args) =>
- ("Apply", EMPTY)
-
- case ApplyDynamic(qual, args) =>
- ("Apply", EMPTY)
-
- case Super(qualif, mix) =>
- ("Super", newTermName("mix: " + mix))
-
- case This(qualifier) =>
- ("This", qualifier)
-
- case Select(qualifier, selector) =>
- ("Select", selector)
-
- case Ident(name) =>
- ("Ident", name)
-
- case Literal(value) =>
- ("Literal", EMPTY)
-
- case TypeTree() =>
- ("TypeTree", EMPTY)
-
- case Annotated(annot, arg) =>
- ("Annotated", EMPTY)
-
- case SingletonTypeTree(ref) =>
- ("SingletonType", EMPTY)
-
- case SelectFromTypeTree(qualifier, selector) =>
- ("SelectFromType", selector)
-
- case CompoundTypeTree(template) =>
- ("CompoundType", EMPTY)
-
- case AppliedTypeTree(tpe, args) =>
- ("AppliedType", EMPTY)
-
- case TypeBoundsTree(lo, hi) =>
- ("TypeBoundsTree", EMPTY)
-
- case ExistentialTypeTree(tpt, whereClauses) =>
- ("ExistentialTypeTree", EMPTY)
-
- case Try(block, catcher, finalizer) =>
- ("Try", EMPTY)
-
- case EmptyTree =>
- ("Empty", EMPTY)
-
- case ArrayValue(elemtpt, trees) =>
- ("ArrayValue", EMPTY)
-
- case Star(t) =>
- ("Star", EMPTY)
- }
+ def treeName(t: Tree): (String, Name) = ((t.printingPrefix, t match {
+ case UnitTree(unit) => newTermName("" + unit)
+ case Super(_, mix) => newTermName("mix: " + mix)
+ case This(qual) => qual
+ case Select(_, selector) => selector
+ case Ident(name) => name
+ case SelectFromTypeTree(_, selector) => selector
+ case x: DefTree => x.name
+ case _ => EMPTY
+ }))
/** Return a list of children for the given tree node */
def children(t: Tree): List[Tree] = t match {
diff --git a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
index 0d19b781e2..8703de4e18 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
@@ -44,6 +44,11 @@ trait TreeDSL {
def NULL = LIT(null)
def UNIT = LIT(())
+ // for those preferring boring, predictable lives, without the thrills of tree-sharing
+ // (but with the perk of typed trees)
+ def TRUE_typed = LIT(true) setType ConstantType(Constant(true))
+ def FALSE_typed = LIT(false) setType ConstantType(Constant(false))
+
object WILD {
def empty = Ident(nme.WILDCARD)
def apply(tpe: Type) = Ident(nme.WILDCARD) setType tpe
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index 6d95b6ffdd..ad26ccad5e 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -65,6 +65,12 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL {
case _ => tree
}
+ def mkSynthSwitchSelector(expr: Tree): Tree = atPos(expr.pos) {
+ // This can't be "Annotated(New(SwitchClass), expr)" because annotations
+ // are very picky about things and it crashes the compiler with "unexpected new".
+ Annotated(Ident(nme.synthSwitch), expr)
+ }
+
// must be kept in synch with the codegen in PatMatVirtualiser
object VirtualCaseDef {
def unapply(b: Block): Option[(Assign, Tree, Tree)] = b match {
@@ -73,6 +79,8 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL {
}
}
+ def hasSynthCaseSymbol(t: Tree) = (t.symbol ne null) && (t.symbol hasFlag (CASE | SYNTHETIC))
+
// TODO: would be so much nicer if we would know during match-translation (i.e., type checking)
// whether we should emit missingCase-style apply (and isDefinedAt), instead of transforming trees post-factum
class MatchMatcher {
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index ccebcfa54d..45325b4694 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -1394,13 +1394,7 @@ self =>
}
}
} else if (in.token == MATCH) {
- t = atPos(t.pos.startOrPoint, in.skipToken()) {
- /** For debugging pattern matcher transition issues */
- if (settings.Ypmatnaive.value)
- makeSequencedMatch(stripParens(t), inBracesOrNil(caseClauses()))
- else
- Match(stripParens(t), inBracesOrNil(caseClauses()))
- }
+ t = atPos(t.pos.startOrPoint, in.skipToken())(Match(stripParens(t), inBracesOrNil(caseClauses())))
}
// in order to allow anonymous functions as statements (as opposed to expressions) inside
// templates, we have to disambiguate them from self type declarations - bug #1565
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
index 0d2fbc5372..3a6e26d3b5 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
@@ -262,29 +262,25 @@ abstract class TreeBuilder {
else if (stats.length == 1) stats.head
else Block(stats.init, stats.last)
+ def makeFilter(tree: Tree, condition: Tree, scrutineeName: String): Tree = {
+ val cases = List(
+ CaseDef(condition, EmptyTree, Literal(Constant(true))),
+ CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false)))
+ )
+ val matchTree = makeVisitor(cases, false, scrutineeName)
+
+ atPos(tree.pos)(Apply(Select(tree, nme.withFilter), matchTree :: Nil))
+ }
+
/** Create tree for for-comprehension generator <val pat0 <- rhs0> */
def makeGenerator(pos: Position, pat: Tree, valeq: Boolean, rhs: Tree): Enumerator = {
val pat1 = patvarTransformer.transform(pat)
val rhs1 =
- if (valeq) rhs
- else matchVarPattern(pat1) match {
- case Some(_) =>
- rhs
- case None =>
- atPos(rhs.pos) {
- Apply(
- Select(rhs, nme.filter),
- List(
- makeVisitor(
- List(
- CaseDef(pat1.duplicate, EmptyTree, Literal(Constant(true))),
- CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false)))),
- false,
- nme.CHECK_IF_REFUTABLE_STRING
- )))
- }
- }
- if (valeq) ValEq(pos, pat1, rhs1) else ValFrom(pos, pat1, rhs1)
+ if (valeq || treeInfo.isVariablePattern(pat)) rhs
+ else makeFilter(rhs, pat1.duplicate, nme.CHECK_IF_REFUTABLE_STRING)
+
+ if (valeq) ValEq(pos, pat1, rhs1)
+ else ValFrom(pos, pat1, rhs1)
}
def makeParam(pname: TermName, tpe: Tree) =
@@ -509,37 +505,6 @@ abstract class TreeBuilder {
def makePatDef(pat: Tree, rhs: Tree): List[Tree] =
makePatDef(Modifiers(0), pat, rhs)
- /** For debugging only. Desugar a match statement like so:
- * val x = scrutinee
- * x match {
- * case case1 => ...
- * case _ => x match {
- * case case2 => ...
- * case _ => x match ...
- * }
- * }
- *
- * This way there are never transitions between nontrivial casedefs.
- * Of course many things break: exhaustiveness and unreachable checking
- * do not work, no switches will be generated, etc.
- */
- def makeSequencedMatch(selector: Tree, cases: List[CaseDef]): Tree = {
- require(cases.nonEmpty)
-
- val selectorName = freshTermName()
- val valdef = atPos(selector.pos)(ValDef(Modifiers(PrivateLocal | SYNTHETIC), selectorName, TypeTree(), selector))
- val nselector = Ident(selectorName)
-
- def loop(cds: List[CaseDef]): Match = {
- def mkNext = CaseDef(Ident(nme.WILDCARD), EmptyTree, loop(cds.tail))
-
- if (cds.size == 1) Match(nselector, cds)
- else Match(selector, List(cds.head, mkNext))
- }
-
- Block(List(valdef), loop(cases))
- }
-
/** Create tree for pattern definition <mods val pat0 = rhs> */
def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree): List[Tree] = matchVarPattern(pat) match {
case Some((name, tpt)) =>
diff --git a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
index 68c4ac03f6..4f3b0bf951 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
@@ -386,10 +386,16 @@ trait BasicBlocks {
def close() {
assert(!closed || ignore, this)
assert(instructionList.nonEmpty, "Empty block: " + this)
- closed = true
- setFlag(DIRTYSUCCS)
- instructionList = instructionList.reverse
- instrs = instructionList.toArray
+ if (ignore && closed) { // redundant `ignore &&` for clarity -- we should never be in state `!ignore && closed`
+ // not doing anything to this block is important...
+ // because the else branch reverses innocent blocks, which is wrong when they're in ignore mode (and closed)
+ // reversing the instructions when (closed && ignore) wreaks havoc for nested label jumps (see comments in genLoad)
+ } else {
+ closed = true
+ setFlag(DIRTYSUCCS)
+ instructionList = instructionList.reverse
+ instrs = instructionList.toArray
+ }
}
def open() {
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 9e801e3ea8..8e568eca79 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -868,6 +868,13 @@ abstract class GenICode extends SubComponent {
abort("Unknown label target: " + sym + " at: " + (fun.pos) + ": ctx: " + ctx)
}
})
+ // note: when one of the args to genLoadLabelArguments is a jump to a label,
+ // it will call back into genLoad and arrive at this case, which will then set ctx1.bb.ignore to true,
+ // this is okay, since we're jumping unconditionally, so the loads and jumps emitted by the outer
+ // call to genLoad (by calling genLoadLabelArguments and emitOnly) can safely be ignored,
+ // however, as emitOnly will close the block, which reverses its instructions (when it's still open),
+ // we better not reverse when the block has already been closed but is in ignore mode
+ // (if it's not in ignore mode, double-closing is an error)
val ctx1 = genLoadLabelArguments(args, label, ctx)
ctx1.bb.emitOnly(if (label.anchored) JUMP(label.block) else PJUMP(label))
ctx1.bb.enterIgnoreMode
@@ -937,11 +944,10 @@ abstract class GenICode extends SubComponent {
"Trying to access the this of another class: " +
"tree.symbol = " + tree.symbol + ", ctx.clazz.symbol = " + ctx.clazz.symbol + " compilation unit:"+unit)
if (tree.symbol.isModuleClass && tree.symbol != ctx.clazz.symbol) {
- debuglog("LOAD_MODULE from 'This': " + tree.symbol);
- assert(!tree.symbol.isPackageClass, "Cannot use package as value: " + tree)
- genLoadModule(ctx, tree.symbol, tree.pos)
+ genLoadModule(ctx, tree)
generatedType = REFERENCE(tree.symbol)
- } else {
+ }
+ else {
ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos)
generatedType = REFERENCE(
if (tree.symbol == ArrayClass) ObjectClass else ctx.clazz.symbol
@@ -954,11 +960,7 @@ abstract class GenICode extends SubComponent {
"Selection of non-module from empty package: " + tree +
" sym: " + tree.symbol + " at: " + (tree.pos)
)
- debuglog("LOAD_MODULE from Select(<emptypackage>): " + tree.symbol)
-
- assert(!tree.symbol.isPackageClass, "Cannot use package as value: " + tree)
- genLoadModule(ctx, tree.symbol, tree.pos)
- ctx
+ genLoadModule(ctx, tree)
case Select(qualifier, selector) =>
val sym = tree.symbol
@@ -966,14 +968,13 @@ abstract class GenICode extends SubComponent {
val hostClass = qualifier.tpe.typeSymbol.orElse(sym.owner)
if (sym.isModule) {
- debuglog("LOAD_MODULE from Select(qualifier, selector): " + sym)
- assert(!tree.symbol.isPackageClass, "Cannot use package as value: " + tree)
- genLoadModule(ctx, sym, tree.pos)
- ctx
- } else if (sym.isStaticMember) {
+ genLoadModule(ctx, tree)
+ }
+ else if (sym.isStaticMember) {
ctx.bb.emit(LOAD_FIELD(sym, true) setHostClass hostClass, tree.pos)
ctx
- } else {
+ }
+ else {
val ctx1 = genLoadQualifier(tree, ctx)
ctx1.bb.emit(LOAD_FIELD(sym, false) setHostClass hostClass, tree.pos)
ctx1
@@ -983,11 +984,10 @@ abstract class GenICode extends SubComponent {
val sym = tree.symbol
if (!sym.isPackage) {
if (sym.isModule) {
- debuglog("LOAD_MODULE from Ident(name): " + sym)
- assert(!sym.isPackageClass, "Cannot use package as value: " + tree)
- genLoadModule(ctx, sym, tree.pos)
+ genLoadModule(ctx, tree)
generatedType = toTypeKind(sym.info)
- } else {
+ }
+ else {
try {
val Some(l) = ctx.method.lookupLocal(sym)
ctx.bb.emit(LOAD_LOCAL(l), tree.pos)
@@ -1200,8 +1200,19 @@ abstract class GenICode extends SubComponent {
genLoad(arg, res, toTypeKind(tpe))
}
- private def genLoadModule(ctx: Context, sym: Symbol, pos: Position) {
- ctx.bb.emit(LOAD_MODULE(sym), pos)
+ private def genLoadModule(ctx: Context, tree: Tree): Context = {
+ // Working around SI-5604. Rather than failing the compile when we see
+ // a package here, check if there's a package object.
+ val sym = (
+ if (!tree.symbol.isPackageClass) tree.symbol
+ else tree.symbol.info.member(nme.PACKAGE) match {
+ case NoSymbol => assert(false, "Cannot use package as value: " + tree) ; NoSymbol
+ case s => Console.err.println("Bug: found package class where package object expected. Converting.") ; s.moduleClass
+ }
+ )
+ debuglog("LOAD_MODULE from %s: %s".format(tree.shortClass, sym))
+ ctx.bb.emit(LOAD_MODULE(sym), tree.pos)
+ ctx
}
def genConversion(from: TypeKind, to: TypeKind, ctx: Context, cast: Boolean) = {
@@ -1560,9 +1571,10 @@ abstract class GenICode extends SubComponent {
val ctx1 = genLoad(l, ctx, ObjectReference)
val ctx2 = genLoad(r, ctx1, ObjectReference)
- ctx2.bb.emit(CALL_METHOD(equalsMethod, if (settings.optimise.value) Dynamic else Static(false)))
- ctx2.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL))
- ctx2.bb.close
+ ctx2.bb.emitOnly(
+ CALL_METHOD(equalsMethod, if (settings.optimise.value) Dynamic else Static(false)),
+ CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL)
+ )
}
else {
if (isNull(l))
diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala
index 877c51ebc1..d31eafff48 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala
@@ -645,7 +645,7 @@ abstract class TypeFlowAnalysis {
} while(!done)
lastInstruction.clear()
- for(b <- isOnPerimeter; val lastIns = b.toList.reverse find isOnWatchlist) {
+ for (b <- isOnPerimeter; lastIns = b.toList.reverse find isOnWatchlist) {
lastInstruction += (b -> lastIns.get.asInstanceOf[opcodes.CALL_METHOD])
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index 4c77cb7082..7b7135d180 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -121,6 +121,9 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
if (settings.debug.value)
inform("[running phase " + name + " on icode]")
+ if (settings.Xverify.value && !SigParser.isParserAvailable)
+ global.warning("signature verification requested by signature parser unavailable: signatures not checked")
+
if (settings.Xdce.value)
for ((sym, cls) <- icodes.classes if inliner.isClosureClass(sym) && !deadCode.liveClosures(sym))
icodes.classes -= sym
@@ -285,6 +288,15 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
val emitLines = debugLevel >= 2
val emitVars = debugLevel >= 3
+ // bug had phase with wrong name; leaving enabled for brief pseudo deprecation
+ private val checkSignatures = (
+ (settings.check containsName phaseName)
+ || (settings.check.value contains "genjvm") && {
+ global.warning("This option will be removed: please use -Ycheck:%s, not -Ycheck:genjvm." format phaseName)
+ true
+ }
+ )
+
/** For given symbol return a symbol corresponding to a class that should be declared as inner class.
*
* For example:
@@ -726,10 +738,10 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
def addGenericSignature(jmember: JMember, sym: Symbol, owner: Symbol) {
if (needsGenericSignature(sym)) {
val memberTpe = beforeErasure(owner.thisType.memberInfo(sym))
- // println("addGenericSignature sym: " + sym.fullName + " : " + memberTpe + " sym.info: " + sym.info)
- // println("addGenericSignature: "+ (sym.ownerChain map (x => (x.name, x.isImplClass))))
+
erasure.javaSig(sym, memberTpe) foreach { sig =>
- debuglog("sig(" + jmember.getName + ", " + sym + ", " + owner + ") " + sig)
+ // This seems useful enough in the general case.
+ log(sig)
/** Since we're using a sun internal class for signature validation,
* we have to allow for it not existing or otherwise malfunctioning:
* in which case we treat every signature as valid. Medium term we
@@ -739,11 +751,11 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
clasz.cunit.warning(sym.pos,
"""|compiler bug: created invalid generic signature for %s in %s
|signature: %s
- |if this is reproducible, please report bug at http://lampsvn.epfl.ch/trac/scala
+ |if this is reproducible, please report bug at https://issues.scala-lang.org/
""".trim.stripMargin.format(sym, sym.owner.skipPackageObject.fullName, sig))
return
}
- if ((settings.check.value contains "genjvm")) {
+ if (checkSignatures) {
val normalizedTpe = beforeErasure(erasure.prepareSigMap(memberTpe))
val bytecodeTpe = owner.thisType.memberInfo(sym)
if (!sym.isType && !sym.isConstructor && !(erasure.erasure(sym)(normalizedTpe) =:= bytecodeTpe)) {
@@ -753,7 +765,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
|original type: %s
|normalized type: %s
|erasure type: %s
- |if this is reproducible, please report bug at http://lampsvn.epfl.ch/trac/scala
+ |if this is reproducible, please report bug at https://issues.scala-lang.org/
""".trim.stripMargin.format(sym, sym.owner.skipPackageObject.fullName, sig, memberTpe, normalizedTpe, bytecodeTpe))
return
}
@@ -871,7 +883,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
debuglog("Adding field: " + f.symbol.fullName)
val jfield = jclass.addNewField(
- javaFlags(f.symbol) | javaFieldFlags(f.symbol),
+ javaFieldFlags(f.symbol),
javaName(f.symbol),
javaType(f.symbol.tpe)
)
@@ -1915,16 +1927,30 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
val privateFlag =
sym.isPrivate || (sym.isPrimaryConstructor && isTopLevelModule(sym.owner))
- // This does not check .isFinal (which checks flags for the FINAL flag),
- // instead checking rawflags for that flag so as to exclude symbols which
- // received lateFINAL. These symbols are eligible for inlining, but to
- // avoid breaking proxy software which depends on subclassing, we avoid
- // insisting on their finality in the bytecode.
+ // Final: the only fields which can receive ACC_FINAL are eager vals.
+ // Neither vars nor lazy vals can, because:
+ //
+ // Source: http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5.3
+ // "Another problem is that the specification allows aggressive
+ // optimization of final fields. Within a thread, it is permissible to
+ // reorder reads of a final field with those modifications of a final
+ // field that do not take place in the constructor."
+ //
+ // A var or lazy val which is marked final still has meaning to the
+ // scala compiler. The word final is heavily overloaded unfortunately;
+ // for us it means "not overridable". At present you can't override
+ // vars regardless; this may change.
+ //
+ // The logic does not check .isFinal (which checks flags for the FINAL flag,
+ // and includes symbols marked lateFINAL) instead inspecting rawflags so
+ // we can exclude lateFINAL. Such symbols are eligible for inlining, but to
+ // avoid breaking proxy software which depends on subclassing, we do not
+ // emit ACC_FINAL.
val finalFlag = (
((sym.rawflags & (Flags.FINAL | Flags.MODULE)) != 0)
&& !sym.enclClass.isInterface
&& !sym.isClassConstructor
- && !sym.isMutable // fix for SI-3569, it is too broad?
+ && !sym.isMutable // lazy vals and vars both
)
mkFlags(
@@ -1939,13 +1965,13 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
if (sym.hasFlag(Flags.SYNCHRONIZED)) JAVA_ACC_SYNCHRONIZED else 0
)
}
- def javaFieldFlags(sym: Symbol) = {
- mkFlags(
+ def javaFieldFlags(sym: Symbol) = (
+ javaFlags(sym) | mkFlags(
if (sym hasAnnotation TransientAttr) ACC_TRANSIENT else 0,
if (sym hasAnnotation VolatileAttr) ACC_VOLATILE else 0,
if (sym.isMutable) 0 else ACC_FINAL
)
- }
+ )
def isTopLevelModule(sym: Symbol): Boolean =
afterPickler { sym.isModuleClass && !sym.isImplClass && !sym.isNestedClass }
diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
index a734b2b92b..dfe9081ee5 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
@@ -262,7 +262,7 @@ abstract class Inliners extends SubComponent {
def inlineWithoutTFA(inputBlocks: Traversable[BasicBlock], callsites: Function1[BasicBlock, List[opcodes.CALL_METHOD]]): Int = {
var inlineCount = 0
import scala.util.control.Breaks._
- for(x <- inputBlocks; val easyCake = callsites(x); if easyCake.nonEmpty) {
+ for(x <- inputBlocks; easyCake = callsites(x); if easyCake.nonEmpty) {
breakable {
for(ocm <- easyCake) {
assert(ocm.method.isEffectivelyFinal && ocm.method.owner.isEffectivelyFinal)
diff --git a/src/compiler/scala/tools/nsc/doc/DocFactory.scala b/src/compiler/scala/tools/nsc/doc/DocFactory.scala
index 9a025b0d14..f32564f097 100644
--- a/src/compiler/scala/tools/nsc/doc/DocFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/DocFactory.scala
@@ -8,7 +8,7 @@ package doc
import scala.util.control.ControlThrowable
import reporters.Reporter
-import util.NoPosition
+import util.{ NoPosition, BatchSourceFile}
import io.{ File, Directory }
import DocParser.Parsed
@@ -46,13 +46,19 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor
override def forScaladoc = true
}
- /** Creates a scaladoc site for all symbols defined in this call's `files`,
- * as well as those defined in `files` of previous calls to the same processor.
+ /** Creates a scaladoc site for all symbols defined in this call's `source`,
+ * as well as those defined in `sources` of previous calls to the same processor.
* @param files The list of paths (relative to the compiler's source path,
* or absolute) of files to document. */
- def makeUniverse(files: List[String]): Option[Universe] = {
+ def makeUniverse(source: Either[List[String], String]): Option[Universe] = {
assert(settings.docformat.value == "html")
- new compiler.Run() compile files
+ source match {
+ case Left(files) =>
+ new compiler.Run() compile files
+ case Right(sourceCode) =>
+ new compiler.Run() compileSources List(new BatchSourceFile("newSource", sourceCode))
+ }
+
if (reporter.hasErrors)
return None
@@ -111,7 +117,7 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor
docletInstance match {
case universer: Universer =>
- val universe = makeUniverse(files) getOrElse { throw NoCompilerRunException }
+ val universe = makeUniverse(Left(files)) getOrElse { throw NoCompilerRunException }
universer setUniverse universe
docletInstance match {
diff --git a/src/compiler/scala/tools/nsc/doc/Settings.scala b/src/compiler/scala/tools/nsc/doc/Settings.scala
index 6c74951156..45a2ad78b4 100644
--- a/src/compiler/scala/tools/nsc/doc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/doc/Settings.scala
@@ -97,4 +97,6 @@ class Settings(error: String => Unit) extends scala.tools.nsc.Settings(error) {
docformat, doctitle, docfooter, docversion, docUncompilable, docsourceurl, docgenerator
)
val isScaladocSpecific: String => Boolean = scaladocSpecific map (_.name)
+
+ override def isScaladoc = true
}
diff --git a/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala b/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala
index 4f05678d85..0116e02e0e 100644
--- a/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala
@@ -119,7 +119,7 @@ class HtmlFactory(val universe: doc.Universe, index: doc.Index) {
def writeTemplate(tpl: DocTemplateEntity) {
if (!(written contains tpl)) {
- writeForThis(new page.Template(tpl))
+ writeForThis(new page.Template(universe, tpl))
written += tpl
tpl.templates map writeTemplate
}
diff --git a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala
index b58c71eaa9..1544dafc69 100644
--- a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala
@@ -22,6 +22,16 @@ abstract class HtmlPage extends Page { thisPage =>
/** The title of this page. */
protected def title: String
+ /** The page description */
+ protected def description: String =
+ // unless overwritten, will display the title in a spaced format, keeping - and .
+ title.replaceAll("[^a-zA-Z0-9\\.\\-]+", " ").replaceAll("\\-+", " - ").replaceAll(" +", " ")
+
+ /** The page keywords */
+ protected def keywords: String =
+ // unless overwritten, same as description, minus the " - "
+ description.replaceAll(" - ", " ")
+
/** Additional header elements (links, scripts, meta tags, etc.) required for this page. */
protected def headers: NodeSeq
@@ -35,6 +45,8 @@ abstract class HtmlPage extends Page { thisPage =>
<html>
<head>
<title>{ title }</title>
+ <meta name="description" content={ description }/>
+ <meta name="keywords" content={ keywords }/>
<meta http-equiv="content-type" content={ "text/html; charset=" + site.encoding }/>
{ headers }
</head>
diff --git a/src/compiler/scala/tools/nsc/doc/html/SyntaxHigh.scala b/src/compiler/scala/tools/nsc/doc/html/SyntaxHigh.scala
index f19f449d2c..f67abc58da 100644
--- a/src/compiler/scala/tools/nsc/doc/html/SyntaxHigh.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/SyntaxHigh.scala
@@ -219,24 +219,24 @@ private[html] object SyntaxHigh {
parse(" ", i+1)
case '&' =>
parse("&amp;", i+1)
- case '<' =>
+ case '<' if i+1 < buf.length =>
val ch = buf(i+1).toChar
if (ch == '-' || ch == ':' || ch == '%')
parse("<span class=\"kw\">&lt;"+ch+"</span>", i+2)
else
parse("&lt;", i+1)
case '>' =>
- if (buf(i+1) == ':')
+ if (i+1 < buf.length && buf(i+1) == ':')
parse("<span class=\"kw\">&gt;:</span>", i+2)
else
parse("&gt;", i+1)
case '=' =>
- if (buf(i+1) == '>')
+ if (i+1 < buf.length && buf(i+1) == '>')
parse("<span class=\"kw\">=&gt;</span>", i+2)
else
parse(buf(i).toChar.toString, i+1)
case '/' =>
- if (buf(i+1) == '/' || buf(i+1) == '*') {
+ if (i+1 < buf.length && (buf(i+1) == '/' || buf(i+1) == '*')) {
val c = comment(i+1)
parse("<span class=\"cmt\">"+c+"</span>", i+c.length)
} else
@@ -257,9 +257,9 @@ private[html] object SyntaxHigh {
else
parse(buf(i).toChar.toString, i+1)
case _ =>
- if (i == 0 || !Character.isJavaIdentifierPart(buf(i-1).toChar)) {
+ if (i == 0 || (i >= 1 && !Character.isJavaIdentifierPart(buf(i-1).toChar))) {
if (Character.isDigit(buf(i)) ||
- (buf(i) == '.' && Character.isDigit(buf(i+1)))) {
+ (buf(i) == '.' && i + 1 < buf.length && Character.isDigit(buf(i+1)))) {
val s = numlit(i)
parse("<span class=\"num\">"+s+"</span>", i+s.length)
} else {
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 e35286b281..f059b5c0cb 100644
--- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala
@@ -11,13 +11,19 @@ package page
import model._
import scala.xml.{ NodeSeq, Text, UnprefixedAttribute }
-class Template(tpl: DocTemplateEntity) extends HtmlPage {
+class Template(universe: doc.Universe, tpl: DocTemplateEntity) extends HtmlPage {
val path =
templateToPath(tpl)
- val title =
- tpl.qualifiedName
+ def title = {
+ val s = universe.settings
+
+ tpl.name +
+ ( if (!s.doctitle.isDefault) " - " + s.doctitle.value else "" ) +
+ ( if (!s.docversion.isDefault) (" " + s.docversion.value) else "" ) +
+ " - " + tpl.qualifiedName
+ }
val headers =
<xml:group>
@@ -29,7 +35,7 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage {
</xml:group>
val valueMembers =
- tpl.methods.filterNot(_.isBridge) ++ tpl.values ++ tpl.templates.filter(x => x.isObject || x.isPackage) sorted
+ tpl.methods ++ tpl.values ++ tpl.templates.filter(x => x.isObject || x.isPackage) sorted
val (absValueMembers, nonAbsValueMembers) =
valueMembers partition (_.isAbstract)
@@ -339,6 +345,17 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage {
}
}
+ val fullSignature: Seq[scala.xml.Node] = {
+ mbr match {
+ case nte: NonTemplateMemberEntity if nte.isUseCase =>
+ <div class="full-signature-block toggleContainer">
+ <span class="toggle">Full Signature</span>
+ <div class="hiddenContent full-signature-usecase">{ signature(nte.useCaseOf.get,true) }</div>
+ </div>
+ case _ => NodeSeq.Empty
+ }
+ }
+
val selfType: Seq[scala.xml.Node] = mbr match {
case dtpl: DocTemplateEntity if (isSelf && !dtpl.selfType.isEmpty && !isReduced) =>
<dt>Self Type</dt>
@@ -372,7 +389,7 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage {
case dtpl: DocTemplateEntity if (isSelf && dtpl.sourceUrl.isDefined && dtpl.inSource.isDefined && !isReduced) =>
val (absFile, line) = dtpl.inSource.get
<dt>Source</dt>
- <dd>{ <a href={ dtpl.sourceUrl.get.toString }>{ Text(absFile.file.getName) }</a> }</dd>
+ <dd>{ <a href={ dtpl.sourceUrl.get.toString } target="_blank">{ Text(absFile.file.getName) }</a> }</dd>
case _ => NodeSeq.Empty
}
@@ -460,7 +477,7 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage {
}
// end attributes block vals ---
- val attributesInfo = attributes ++ definitionClasses ++ selfType ++ annotations ++ deprecation ++ migration ++ sourceLink ++ mainComment
+ val attributesInfo = attributes ++ definitionClasses ++ fullSignature ++ selfType ++ annotations ++ deprecation ++ migration ++ sourceLink ++ mainComment
val attributesBlock =
if (attributesInfo.isEmpty)
NodeSeq.Empty
diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.css b/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.css
index 4f552b7169..6fb83c133e 100644
--- a/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.css
+++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.css
@@ -340,6 +340,30 @@ div.members > ol > li:last-child {
color: darkgreen;
}
+.full-signature-usecase h4 span {
+ font-size: 10pt;
+}
+
+.full-signature-usecase > #signature {
+ padding-top: 0px;
+}
+
+#template .full-signature-usecase > .signature.closed {
+ background: none;
+}
+
+#template .full-signature-usecase > .signature.opened {
+ background: none;
+}
+
+.full-signature-block {
+ padding: 5px 0 0;
+ border-top: 1px solid #EBEBEB;
+ margin-top: 5px;
+ margin-bottom: 5px;
+}
+
+
/* Comments text formating */
.cmt {}
diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
index 496d004fd8..702d643fb4 100644
--- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
@@ -247,7 +247,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
protected lazy val memberSyms =
// Only this class's constructors are part of its members, inherited constructors are not.
- sym.info.members.filter(s => localShouldDocument(s) && (!s.isConstructor || s.owner == sym))
+ sym.info.members.filter(s => localShouldDocument(s) && (!s.isConstructor || s.owner == sym) && !isPureBridge(sym) )
val members = memberSyms flatMap (makeMember(_, this))
val templates = members collect { case c: DocTemplateEntity => c }
@@ -620,7 +620,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
case tp: TypeRef if definitions.isByNameParamType(tp) =>
nameBuffer append "⇒ "
appendType0(tp.args.head)
- case tp: TypeRef if definitions.isTupleTypeOrSubtype(tp) =>
+ case tp: TypeRef if definitions.isTupleType(tp) =>
val args = tp.normalize.typeArgs
nameBuffer append '('
appendTypes0(args, ", ")
@@ -705,4 +705,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
def localShouldDocument(aSym: Symbol): Boolean = {
!aSym.isPrivate && (aSym.isProtected || aSym.privateWithin == NoSymbol) && !aSym.isSynthetic
}
+
+ /** Filter '@bridge' methods only if *they don't override non-bridge methods*. See SI-5373 for details */
+ def isPureBridge(sym: Symbol) = sym.isBridge && sym.allOverriddenSymbols.forall(_.isBridge)
}
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 b088c643cb..bc5cd4a958 100644
--- a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala
@@ -491,7 +491,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
else
jump("}}}")
blockEnded("code block")
- Code(getRead)
+ Code(normalizeIndentation(getRead))
}
/** {{{ title ::= ('=' inline '=' | "==" inline "==" | ...) '\n' }}} */
@@ -732,6 +732,64 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
nextChar()
}
+ /**
+ * Eliminates the (common) leading spaces in all lines, based on the first line
+ * For indented pieces of code, it reduces the indent to the least whitespace prefix:
+ * {{{
+ * indented example
+ * another indented line
+ * if (condition)
+ * then do something;
+ * ^ this is the least whitespace prefix
+ * }}}
+ */
+ def normalizeIndentation(_code: String): String = {
+
+ var code = _code.trim
+ var maxSkip = Integer.MAX_VALUE
+ var crtSkip = 0
+ var wsArea = true
+ var index = 0
+ var firstLine = true
+ var emptyLine = true
+
+ while (index < code.length) {
+ code(index) match {
+ case ' ' =>
+ if (wsArea)
+ crtSkip += 1
+ case c =>
+ wsArea = (c == '\n')
+ maxSkip = if (firstLine || emptyLine) maxSkip else if (maxSkip <= crtSkip) maxSkip else crtSkip
+ crtSkip = if (c == '\n') 0 else crtSkip
+ firstLine = if (c == '\n') false else firstLine
+ emptyLine = if (c == '\n') true else false
+ }
+ index += 1
+ }
+
+ if (maxSkip == 0)
+ code
+ else {
+ index = 0
+ val builder = new StringBuilder
+ while (index < code.length) {
+ builder.append(code(index))
+ if (code(index) == '\n') {
+ // we want to skip as many spaces are available, if there are less spaces (like on empty lines, do not
+ // over-consume them)
+ index += 1
+ val limit = index + maxSkip
+ while ((index < code.length) && (code(index) == ' ') && index < limit)
+ index += 1
+ }
+ else
+ index += 1
+ }
+ builder.toString
+ }
+ }
+
def checkParaEnded(): Boolean = {
(char == endOfText) ||
((char == endOfLine) && {
diff --git a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala
index d08a363a9d..88e3827403 100644
--- a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala
+++ b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala
@@ -189,7 +189,7 @@ self: scala.tools.nsc.Global =>
override def validatePositions(tree: Tree) {
def reportTree(prefix : String, tree : Tree) {
val source = if (tree.pos.isDefined) tree.pos.source else ""
- inform("== "+prefix+" tree ["+tree.id+"] of type "+tree.productPrefix+" at "+tree.pos.show+source)
+ inform("== "+prefix+" tree ["+tree.id+"] of type "+tree.printingPrefix+" at "+tree.pos.show+source)
inform("")
inform(treeStatus(tree))
inform("")
diff --git a/src/compiler/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala b/src/compiler/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala
index 33ef4a432d..2f47685757 100644
--- a/src/compiler/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala
@@ -6,8 +6,8 @@
package scala.tools.nsc
package interpreter
-class AbstractOrMissingHandler[T](onError: String => Unit, value: T) extends scala.runtime.AbstractPartialFunction[Throwable, T] {
- def _isDefinedAt(t: Throwable) = t match {
+class AbstractOrMissingHandler[T](onError: String => Unit, value: T) extends PartialFunction[Throwable, T] {
+ def isDefinedAt(t: Throwable) = t match {
case _: AbstractMethodError => true
case _: NoSuchMethodError => true
case _: MissingRequirementError => true
diff --git a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
index 015dc2a7f1..808f549304 100644
--- a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
@@ -15,7 +15,7 @@ trait CompletionOutput {
val global: Global
import global._
- import definitions.{ isTupleTypeOrSubtype, isFunctionType, isRepeatedParamType }
+ import definitions.{ isTupleType, isFunctionType, isRepeatedParamType }
/** Reducing fully qualified noise for some common packages.
*/
@@ -48,11 +48,11 @@ trait CompletionOutput {
def typeToString(tp: Type): String = relativize(
tp match {
- case x if isFunctionType(x) => functionString(x)
- case x if isTupleTypeOrSubtype(x) => tupleString(x)
- case x if isRepeatedParamType(x) => typeToString(x.typeArgs.head) + "*"
- case mt @ MethodType(_, _) => methodTypeToString(mt)
- case x => x.toString
+ case x if isFunctionType(x) => functionString(x)
+ case x if isTupleType(x) => tupleString(x)
+ case x if isRepeatedParamType(x) => typeToString(x.typeArgs.head) + "*"
+ case mt @ MethodType(_, _) => methodTypeToString(mt)
+ case x => x.toString
}
)
diff --git a/src/compiler/scala/tools/nsc/interpreter/Naming.scala b/src/compiler/scala/tools/nsc/interpreter/Naming.scala
index 8e215cf63b..19266442cb 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Naming.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Naming.scala
@@ -11,16 +11,18 @@ package interpreter
*/
trait Naming {
def unmangle(str: String): String = {
+ val ESC = '\u001b'
val cleaned = removeIWPackages(removeLineWrapper(str))
- var ctrlChars = 0
- cleaned map { ch =>
- if (ch.isControl && !ch.isWhitespace) {
- ctrlChars += 1
- if (ctrlChars > 5) return "[line elided for control chars: possibly a scala signature]"
- else '?'
- }
- else ch
- }
+ // Looking to exclude binary data which hoses the terminal, but
+ // let through the subset of it we need, like whitespace and also
+ // <ESC> for ansi codes.
+ val binaryChars = cleaned count (ch => ch < 32 && !ch.isWhitespace && ch != ESC)
+ // Lots of binary chars - translate all supposed whitespace into spaces
+ if (binaryChars > 5)
+ cleaned map (ch => if (ch.isWhitespace) ' ' else if (ch < 32) '?' else ch)
+ // Not lots - preserve whitespace and ESC
+ else
+ cleaned map (ch => if (ch.isWhitespace || ch == ESC) ch else if (ch < 32) '?' else ch)
}
// The two name forms this is catching are the two sides of this assignment:
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
index 1285e29d4a..43aad9f591 100644
--- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
+++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
@@ -309,7 +309,7 @@ trait ParallelMatching extends ast.TreeDSL
}
lazy val cases =
- for ((tag, indices) <- literalMap.toList) yield {
+ for ((tag, indices) <- literalMap.toList.sortBy(_._1)) yield {
val newRows = indices map (i => addDefaultVars(i)(rest rows i))
val r = remake(newRows ++ defaultRows, includeScrut = false)
val r2 = make(r.tvars, r.rows map (x => x rebind bindVars(tag, x.subst)))
@@ -425,7 +425,7 @@ trait ParallelMatching extends ast.TreeDSL
// Should the given pattern join the expanded pivot in the success matrix? If so,
// this partial function will be defined for the pattern, and the result of the apply
// is the expanded sequence of new patterns.
- lazy val successMatrixFn = new scala.runtime.AbstractPartialFunction[Pattern, List[Pattern]] {
+ lazy val successMatrixFn = new PartialFunction[Pattern, List[Pattern]] {
private def seqIsDefinedAt(x: SequenceLikePattern) = (hasStar, x.hasStar) match {
case (true, true) => true
case (true, false) => pivotLen <= x.nonStarLength
@@ -433,7 +433,7 @@ trait ParallelMatching extends ast.TreeDSL
case (false, false) => pivotLen == x.nonStarLength
}
- def _isDefinedAt(pat: Pattern) = pat match {
+ def isDefinedAt(pat: Pattern) = pat match {
case x: SequenceLikePattern => seqIsDefinedAt(x)
case WildcardPattern() => true
case _ => false
diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala
index 8bdf83fda4..4f6a4c8dc0 100644
--- a/src/compiler/scala/tools/nsc/matching/Patterns.scala
+++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala
@@ -343,10 +343,9 @@ trait Patterns extends ast.TreeDSL {
def apply(x: Apply): Pattern = {
val Apply(fn, args) = x
def isModule = x.symbol.isModule || x.tpe.termSymbol.isModule
- def isTuple = isTupleTypeOrSubtype(fn.tpe)
if (fn.isType) {
- if (isTuple) TuplePattern(x)
+ if (isTupleType(fn.tpe)) TuplePattern(x)
else ConstructorPattern(x)
}
else if (args.isEmpty) {
diff --git a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala
index c76a04c6ba..f5335fb0f5 100644
--- a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala
+++ b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala
@@ -8,7 +8,7 @@ package reporters
import java.io.{ BufferedReader, IOException, PrintWriter }
import util._
-import scala.tools.util.StringOps.countElementsAsString
+import scala.tools.util.StringOps
/**
* This class implements a Reporter that displays messages on a text
@@ -40,7 +40,7 @@ class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: Pr
* @return ...
*/
private def getCountString(severity: Severity): String =
- countElementsAsString((severity).count, label(severity))
+ StringOps.countElementsAsString((severity).count, label(severity))
/** Prints the message. */
def printMessage(msg: String) { writer.print(msg + "\n"); writer.flush() }
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 5f3c7ec32c..14b3bcc8ce 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -30,6 +30,22 @@ trait ScalaSettings extends AbsScalaSettings
*/
protected def defaultClasspath = sys.env.getOrElse("CLASSPATH", ".")
+ /** Enabled under -Xexperimental. */
+ protected def experimentalSettings = List[BooleanSetting](YmethodInfer, overrideObjects, overrideVars)
+
+ /** Enabled under -Xfuture. */
+ protected def futureSettings = List[BooleanSetting]()
+
+ /** Enabled under -optimise. */
+ protected def optimiseSettings = List[BooleanSetting](inline, inlineHandlers, Xcloselim, Xdce)
+
+ /** Internal use - syntax enhancements. */
+ private class EnableSettings[T <: Setting](val s: T) {
+ def enabling(toEnable: List[BooleanSetting]): s.type = s withPostSetHook (_ => toEnable foreach (_.value = true))
+ def andThen(f: s.T => Unit): s.type = s withPostSetHook (setting => f(setting.value))
+ }
+ private implicit def installEnableSettings[T <: Setting](s: T) = new EnableSettings(s)
+
/** Disable a setting */
def disable(s: Setting) = allSettings -= s
@@ -43,12 +59,8 @@ trait ScalaSettings extends AbsScalaSettings
*/
// argfiles is only for the help message
val argfiles = BooleanSetting ("@<file>", "A text file containing compiler arguments (options and source files)")
- val classpath = PathSetting ("-classpath", "Specify where to find user class files.", defaultClasspath) .
- withAbbreviation ("-cp")
+ val classpath = PathSetting ("-classpath", "Specify where to find user class files.", defaultClasspath) withAbbreviation "-cp"
val d = OutputSetting (outputDirs, ".")
- val optimise = BooleanSetting ("-optimise", "Generates faster bytecode by applying optimisations to the program") .
- withAbbreviation("-optimize") .
- withPostSetHook(set => List(inline, inlineHandlers, Xcloselim, Xdce) foreach (_.value = set.value))
val nospecialization = BooleanSetting ("-no-specialization", "Ignore @specialize annotations.")
/**
@@ -64,7 +76,6 @@ trait ScalaSettings extends AbsScalaSettings
val elidebelow = IntSetting ("-Xelide-below", "Calls to @elidable methods are omitted if method priority is lower than argument",
elidable.MINIMUM, None, elidable.byName get _)
val noForwarders = BooleanSetting ("-Xno-forwarders", "Do not generate static forwarders in mirror classes.")
- val future = BooleanSetting ("-Xfuture", "Turn on future language features.")
val genPhaseGraph = StringSetting ("-Xgenerate-phase-graph", "file", "Generate the phase graphs (outputs .dot files) to fileX.dot.", "")
val XlogImplicits = BooleanSetting ("-Xlog-implicits", "Show more detail on why some implicits are not applicable.")
val logImplicitConv = BooleanSetting ("-Xlog-implicit-conversions", "Print a message whenever an implicit conversion is inserted.")
@@ -92,12 +103,6 @@ trait ScalaSettings extends AbsScalaSettings
val showPhases = BooleanSetting ("-Xshow-phases", "Print a synopsis of compiler phases.")
val sourceReader = StringSetting ("-Xsource-reader", "classname", "Specify a custom method for reading source files.", "")
- // Experimental Extensions
- val Xexperimental = BooleanSetting ("-Xexperimental", "Enable experimental extensions.") .
- withPostSetHook(set => List(YmethodInfer, overrideObjects) foreach (_.value = set.value))
- // YdepMethTpes, YvirtClasses,
- val Xmacros = BooleanSetting ("-Xmacros", "Enable macros.")
-
/** Compatibility stubs for options whose value name did
* not previously match the option name.
*/
@@ -112,6 +117,7 @@ trait ScalaSettings extends AbsScalaSettings
* -Y "Private" settings
*/
val overrideObjects = BooleanSetting ("-Yoverride-objects", "Allow member objects to be overridden.")
+ val overrideVars = BooleanSetting ("-Yoverride-vars", "Allow vars to be overridden.")
val Yhelp = BooleanSetting ("-Y", "Print a synopsis of private options.")
val browse = PhasesSetting ("-Ybrowse", "Browse the abstract syntax tree after")
val check = PhasesSetting ("-Ycheck", "Check the tree at the end of")
@@ -145,8 +151,7 @@ trait ScalaSettings extends AbsScalaSettings
val Ygenjavap = StringSetting ("-Ygen-javap", "dir", "Generate a parallel output directory of .javap files.", "")
val Ydumpclasses = StringSetting ("-Ydump-classes", "dir", "Dump the generated bytecode to .class files (useful for reflective compilation that utilizes in-memory classloaders).", "")
val Ynosqueeze = BooleanSetting ("-Yno-squeeze", "Disable creation of compact code in matching.")
- val Ystatistics = BooleanSetting ("-Ystatistics", "Print compiler statistics.") .
- withPostSetHook(set => util.Statistics.enabled = set.value)
+ val Ystatistics = BooleanSetting ("-Ystatistics", "Print compiler statistics.") andThen (util.Statistics.enabled = _)
val stopAfter = PhasesSetting ("-Ystop-after", "Stop after") withAbbreviation ("-stop") // backward compat
val stopBefore = PhasesSetting ("-Ystop-before", "Stop before")
val refinementMethodDispatch =
@@ -157,26 +162,11 @@ trait ScalaSettings extends AbsScalaSettings
val YrichExes = BooleanSetting ("-Yrich-exceptions",
"Fancier exceptions. Set source search path with -D" +
sys.SystemProperties.traceSourcePath.key)
- val Yidedebug = BooleanSetting ("-Yide-debug", "Generate, validate and output trees using the interactive compiler.")
- val Ybuilderdebug = ChoiceSetting ("-Ybuilder-debug", "manager", "Compile using the specified build manager.", List("none", "refined", "simple"), "none")
- val Ybuildmanagerdebug =
- BooleanSetting ("-Ybuild-manager-debug", "Generate debug information for the Refined Build Manager compiler.")
- val Ytyperdebug = BooleanSetting ("-Ytyper-debug", "Trace all type assignments.")
- val Yposdebug = BooleanSetting ("-Ypos-debug", "Trace position validation.")
- val Yinferdebug = BooleanSetting ("-Yinfer-debug", "Trace type inference and implicit search.")
- val Ypmatdebug = BooleanSetting ("-Ypmat-debug", "Trace all pattern matcher activity.")
+ val Ybuilderdebug = ChoiceSetting("-Ybuilder-debug", "manager", "Compile using the specified build manager.", List("none", "refined", "simple"), "none")
val Yreifycopypaste =
BooleanSetting ("-Yreify-copypaste", "Dump the reified trees in copypasteable representation.")
- val Yreifydebug = BooleanSetting ("-Yreify-debug", "Trace reification.")
- val Ymacrodebug = BooleanSetting ("-Ymacro-debug", "Trace macro-related activities: generation of synthetics, expansion, exceptions.")
val Yreplsync = BooleanSetting ("-Yrepl-sync", "Do not use asynchronous code for repl startup")
- val Yrepldebug = BooleanSetting ("-Yrepl-debug", "Trace all repl activity.") .
- withPostSetHook(_ => interpreter.replProps.debug setValue true)
- val Ycompletion = BooleanSetting ("-Ycompletion-debug", "Trace all tab completion activity.")
- val Ydocdebug = BooleanSetting ("-Ydoc-debug", "Trace all scaladoc activity.")
- val Ypmatnaive = BooleanSetting ("-Ypmat-naive", "Desugar matches as naively as possible.")
val Ynotnull = BooleanSetting ("-Ynotnull", "Enable (experimental and incomplete) scala.NotNull.")
- // val YdepMethTpes = BooleanSetting ("-Ydependent-method-types", "Allow dependent method types.")
val YmethodInfer = BooleanSetting ("-Yinfer-argument-types", "Infer types for arguments of overriden methods.")
val etaExpandKeepsStar = BooleanSetting("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.")
val noSelfCheck = BooleanSetting ("-Yno-self-type-checks", "Suppress check for self-type conformance among inherited members.")
@@ -188,6 +178,29 @@ trait ScalaSettings extends AbsScalaSettings
def stop = stopAfter
+ /** Area-specific debug output.
+ */
+ val Ybuildmanagerdebug = BooleanSetting("-Ybuild-manager-debug", "Generate debug information for the Refined Build Manager compiler.")
+ val Ycompletion = BooleanSetting("-Ycompletion-debug", "Trace all tab completion activity.")
+ val Ydocdebug = BooleanSetting("-Ydoc-debug", "Trace all scaladoc activity.")
+ val Yidedebug = BooleanSetting("-Yide-debug", "Generate, validate and output trees using the interactive compiler.")
+ val Yinferdebug = BooleanSetting("-Yinfer-debug", "Trace type inference and implicit search.")
+ val Ymacrodebug = BooleanSetting("-Ymacro-debug", "Trace macro-related activities: generation of synthetics, expansion, exceptions.")
+ val Ypmatdebug = BooleanSetting("-Ypmat-debug", "Trace all pattern matcher activity.")
+ val Yposdebug = BooleanSetting("-Ypos-debug", "Trace position validation.")
+ val Yreifydebug = BooleanSetting("-Yreify-debug", "Trace reification.")
+ val Yrepldebug = BooleanSetting("-Yrepl-debug", "Trace all repl activity.") andThen (interpreter.replProps.debug setValue _)
+ val Ytyperdebug = BooleanSetting("-Ytyper-debug", "Trace all type assignments.")
+
+ /** Groups of Settings.
+ */
+ val future = BooleanSetting ("-Xfuture", "Turn on future language features.") enabling futureSettings
+ val optimise = BooleanSetting ("-optimise", "Generates faster bytecode by applying optimisations to the program") withAbbreviation "-optimize" enabling optimiseSettings
+ val Xexperimental = BooleanSetting ("-Xexperimental", "Enable experimental extensions.") enabling experimentalSettings
+
+ // Feature extensions
+ val Xmacros = BooleanSetting ("-Xmacros", "Enable macros.")
+
/**
* IDE-specific settings
*/
@@ -204,4 +217,7 @@ trait ScalaSettings extends AbsScalaSettings
*/
val pluginOptions = MultiStringSetting("-P", "plugin:opt", "Pass an option to a plugin") .
withHelpSyntax("-P:<plugin>:<opt>")
+
+ /** Test whether this is scaladoc we're looking at */
+ def isScaladoc = false
}
diff --git a/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala b/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala
index 59342a36ef..5f7deb87bd 100644
--- a/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala
@@ -105,7 +105,7 @@ abstract class BrowsingLoaders extends SymbolLoaders {
*/
override def enterToplevelsFromSource(root: Symbol, name: String, src: AbstractFile) {
try {
- if (root == definitions.RootClass || root == definitions.EmptyPackageClass)
+ if (root.isEffectiveRoot) // RootClass or EmptyPackageClass
super.enterToplevelsFromSource(root, name, src)
else
browseTopLevel(root, src)
diff --git a/src/compiler/scala/tools/nsc/symtab/Positions.scala b/src/compiler/scala/tools/nsc/symtab/Positions.scala
index c96c709fb0..680b06f8ce 100644
--- a/src/compiler/scala/tools/nsc/symtab/Positions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Positions.scala
@@ -14,6 +14,15 @@ self: scala.tools.nsc.symtab.SymbolTable =>
type Position = scala.tools.nsc.util.Position
val NoPosition = scala.tools.nsc.util.NoPosition
+ type TreeAnnotation = scala.tools.nsc.util.TreeAnnotation
+ val NoTreeAnnotation: TreeAnnotation = NoPosition
+ def positionToAnnotation(pos: Position): TreeAnnotation = pos
+ def annotationToPosition(annot: TreeAnnotation): Position = annot.pos
+ override def _checkSetAnnotation(tree: Tree, annot: TreeAnnotation): Unit = {
+ if (tree.pos != NoPosition && tree.pos != annot.pos) debugwarn("Overwriting annotation "+ tree.annotation +" of tree "+ tree +" with annotation "+ annot)
+ // if ((tree.annotation.isInstanceOf[scala.tools.nsc.util.Position] || !annot.isInstanceOf[scala.tools.nsc.util.Position]) && tree.isInstanceOf[Block])
+ // println("Updating block from "+ tree.annotation +" to "+ annot)
+ }
def focusPos(pos: Position): Position = pos.focus
def isRangePos(pos: Position): Boolean = pos.isRange
def showPos(pos: Position): String = pos.show
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
index 942ec1fa86..7eb04eaf40 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
@@ -30,15 +30,11 @@ abstract class SymbolLoaders {
member
}
- private def realOwner(root: Symbol): Symbol = {
- if (root.isRoot) definitions.EmptyPackageClass else root
- }
-
/** Enter class with given `name` into scope of `root`
* and give them `completer` as type.
*/
def enterClass(root: Symbol, name: String, completer: SymbolLoader): Symbol = {
- val owner = realOwner(root)
+ val owner = root.ownerOfNewSymbols
val clazz = owner.newClass(newTypeName(name))
clazz setInfo completer
enterIfNew(owner, clazz, completer)
@@ -48,7 +44,7 @@ abstract class SymbolLoaders {
* and give them `completer` as type.
*/
def enterModule(root: Symbol, name: String, completer: SymbolLoader): Symbol = {
- val owner = realOwner(root)
+ val owner = root.ownerOfNewSymbols
val module = owner.newModule(newTermName(name))
module setInfo completer
module.moduleClass setInfo moduleClassLoader
@@ -126,9 +122,13 @@ abstract class SymbolLoaders {
ok = false
if (settings.debug.value) ex.printStackTrace()
val msg = ex.getMessage()
- globalError(
- if (msg eq null) "i/o error while loading " + root.name
- else "error while loading " + root.name + ", " + msg);
+ // SI-5593 Scaladoc's current strategy is to visit all packages in search of user code that can be documented
+ // therefore, it will rummage through the classpath triggering errors whenever it encounters package objects
+ // that are not in their correct place (see bug for details)
+ if (!settings.isScaladoc)
+ globalError(
+ if (msg eq null) "i/o error while loading " + root.name
+ else "error while loading " + root.name + ", " + msg);
}
try {
val start = currentTime
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index 1cd4ab21ea..9dee441527 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -433,10 +433,7 @@ abstract class ClassfileParser {
sym.info.decl(part.encode)
}//.suchThat(module == _.isModule)
- sym = (
- if (sym1 ne NoSymbol) sym1
- else sym.info.decl(part.encode.toTypeName)
- )
+ sym = sym1 orElse sym.info.decl(part.encode.toTypeName)
}
}
sym
@@ -446,7 +443,11 @@ abstract class ClassfileParser {
def classNameToSymbol(name: Name): Symbol = {
def loadClassSymbol(name: Name): Symbol = {
val file = global.classPath findSourceFile ("" +name) getOrElse {
- warning("Class " + name + " not found - continuing with a stub.")
+ // SI-5593 Scaladoc's current strategy is to visit all packages in search of user code that can be documented
+ // therefore, it will rummage through the classpath triggering errors whenever it encounters package objects
+ // that are not in their correct place (see bug for details)
+ if (!settings.isScaladoc)
+ warning("Class " + name + " not found - continuing with a stub.")
return NoSymbol.newClass(name.toTypeName)
}
val completer = new global.loaders.ClassfileLoader(file)
diff --git a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala
index e11a5a4ad9..4b847fa94a 100644
--- a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala
@@ -108,7 +108,7 @@ abstract class TypeParser {
val method = new ConstructorInfo(declType, attrs, Array[MSILType]())
val flags = Flags.JAVA
val owner = clazz
- val methodSym = owner.newMethod(NoPosition, nme.CONSTRUCTOR).setFlag(flags)
+ val methodSym = owner.newMethod(nme.CONSTRUCTOR, NoPosition, flags)
val rettype = clazz.tpe
val mtype = methodType(Array[MSILType](), rettype);
val mInfo = mtype(methodSym)
@@ -224,14 +224,14 @@ abstract class TypeParser {
if (canBeTakenAddressOf) {
clazzBoxed.setInfo( if (ownTypeParams.isEmpty) classInfoAsInMetadata
- else polyType(ownTypeParams, classInfoAsInMetadata) )
+ else genPolyType(ownTypeParams, classInfoAsInMetadata) )
clazzBoxed.setFlag(flags)
val rawValueInfoType = ClassInfoType(definitions.anyvalparam, instanceDefs, clazz)
clazz.setInfo( if (ownTypeParams.isEmpty) rawValueInfoType
- else polyType(ownTypeParams, rawValueInfoType) )
+ else genPolyType(ownTypeParams, rawValueInfoType) )
} else {
clazz.setInfo( if (ownTypeParams.isEmpty) classInfoAsInMetadata
- else polyType(ownTypeParams, classInfoAsInMetadata) )
+ else genPolyType(ownTypeParams, classInfoAsInMetadata) )
}
// TODO I don't remember if statics.setInfo and staticModule.setInfo should also know about type params
@@ -284,7 +284,7 @@ abstract class TypeParser {
else
getCLRType(field.FieldType)
val owner = if (field.IsStatic()) statics else clazz;
- val sym = owner.newValue(NoPosition, name).setFlag(flags).setInfo(fieldType);
+ val sym = owner.newValue(name, NoPosition, flags).setInfo(fieldType);
// TODO: set private within!!! -> look at typechecker/Namers.scala
(if (field.IsStatic()) staticDefs else instanceDefs).enter(sym);
clrTypes.fields(sym) = field;
@@ -313,7 +313,7 @@ abstract class TypeParser {
val name: Name = if (gparamsLength == 0) prop.Name else nme.apply;
val flags = translateAttributes(getter);
val owner: Symbol = if (getter.IsStatic) statics else clazz;
- val methodSym = owner.newMethod(NoPosition, name).setFlag(flags)
+ val methodSym = owner.newMethod(name, NoPosition, flags)
val mtype: Type = if (gparamsLength == 0) NullaryMethodType(propType) // .NET properties can't be polymorphic
else methodType(getter, getter.ReturnType)(methodSym)
methodSym.setInfo(mtype);
@@ -337,7 +337,7 @@ abstract class TypeParser {
val flags = translateAttributes(setter);
val mtype = methodType(setter, definitions.UnitClass.tpe);
val owner: Symbol = if (setter.IsStatic) statics else clazz;
- val methodSym = owner.newMethod(NoPosition, name).setFlag(flags)
+ val methodSym = owner.newMethod(name, NoPosition, flags)
methodSym.setInfo(mtype(methodSym))
methodSym.setFlag(Flags.ACCESSOR);
(if (setter.IsStatic) staticDefs else instanceDefs).enter(methodSym);
@@ -424,14 +424,14 @@ abstract class TypeParser {
val flags = Flags.JAVA | Flags.FINAL
for (cmpName <- ENUM_CMP_NAMES) {
- val enumCmp = clazz.newMethod(NoPosition, cmpName)
+ val enumCmp = clazz.newMethod(cmpName)
val enumCmpType = JavaMethodType(enumCmp.newSyntheticValueParams(List(clazz.tpe)), definitions.BooleanClass.tpe)
enumCmp.setFlag(flags).setInfo(enumCmpType)
instanceDefs.enter(enumCmp)
}
for (bitLogName <- ENUM_BIT_LOG_NAMES) {
- val enumBitLog = clazz.newMethod(NoPosition, bitLogName)
+ val enumBitLog = clazz.newMethod(bitLogName)
val enumBitLogType = JavaMethodType(enumBitLog.newSyntheticValueParams(List(clazz.tpe)), clazz.tpe /* was classInfo, infinite typer */)
enumBitLog.setFlag(flags).setInfo(enumBitLogType)
instanceDefs.enter(enumBitLog)
@@ -469,7 +469,7 @@ abstract class TypeParser {
val flags = translateAttributes(method);
val owner = if (method.IsStatic()) statics else clazz;
- val methodSym = owner.newMethod(NoPosition, getName(method)).setFlag(flags)
+ val methodSym = owner.newMethod(getName(method), NoPosition, flags)
/* START CLR generics (snippet 3) */
val newMethodTParams = populateMethodTParams(method, methodSym)
/* END CLR generics (snippet 3) */
@@ -480,7 +480,7 @@ abstract class TypeParser {
val mtype = methodType(method, rettype);
if (mtype == null) return;
/* START CLR generics (snippet 4) */
- val mInfo = if (method.IsGeneric) polyType(newMethodTParams, mtype(methodSym))
+ val mInfo = if (method.IsGeneric) genPolyType(newMethodTParams, mtype(methodSym))
else mtype(methodSym)
/* END CLR generics (snippet 4) */
/* START CLR non-generics (snippet 4)
@@ -500,7 +500,7 @@ abstract class TypeParser {
}
private def createMethod(name: Name, flags: Long, mtype: Symbol => Type, method: MethodInfo, statik: Boolean): Symbol = {
- val methodSym: Symbol = (if (statik) statics else clazz).newMethod(NoPosition, name)
+ val methodSym: Symbol = (if (statik) statics else clazz).newMethod(name)
methodSym.setFlag(flags).setInfo(mtype(methodSym))
(if (statik) staticDefs else instanceDefs).enter(methodSym)
if (method != null)
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index a98cd5c6b1..0c867b9e7e 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -407,6 +407,103 @@ abstract class Erasure extends AddInterfaces
}
}
+ class ComputeBridges(owner: Symbol) {
+ assert(phase == currentRun.erasurePhase, phase)
+
+ var toBeRemoved = immutable.Set[Symbol]()
+ val site = owner.thisType
+ val bridgesScope = newScope
+ val bridgeTarget = mutable.HashMap[Symbol, Symbol]()
+ var bridges = List[Tree]()
+
+ val opc = beforeExplicitOuter {
+ new overridingPairs.Cursor(owner) {
+ override def parents = List(owner.info.firstParent)
+ override def exclude(sym: Symbol) = !sym.isMethod || sym.isPrivate || super.exclude(sym)
+ }
+ }
+
+ def compute(): (List[Tree], immutable.Set[Symbol]) = {
+ while (opc.hasNext) {
+ val member = opc.overriding
+ val other = opc.overridden
+ //println("bridge? " + member + ":" + member.tpe + member.locationString + " to " + other + ":" + other.tpe + other.locationString)//DEBUG
+ if (beforeExplicitOuter(!member.isDeferred))
+ checkPair(member, other)
+
+ opc.next
+ }
+ (bridges, toBeRemoved)
+ }
+
+ def checkPair(member: Symbol, other: Symbol) {
+ val otpe = erasure(owner)(other.tpe)
+ val bridgeNeeded = afterErasure (
+ !(other.tpe =:= member.tpe) &&
+ !(deconstMap(other.tpe) =:= deconstMap(member.tpe)) &&
+ { var e = bridgesScope.lookupEntry(member.name)
+ while ((e ne null) && !((e.sym.tpe =:= otpe) && (bridgeTarget(e.sym) == member)))
+ e = bridgesScope.lookupNextEntry(e)
+ (e eq null)
+ }
+ )
+ if (!bridgeNeeded)
+ return
+
+ val newFlags = (member.flags | BRIDGE) & ~(ACCESSOR | DEFERRED | LAZY | lateDEFERRED)
+ val bridge = other.cloneSymbolImpl(owner, newFlags) setPos owner.pos
+
+ debuglog("generating bridge from %s (%s): %s to %s: %s".format(
+ other, flagsToString(newFlags),
+ otpe + other.locationString, member,
+ erasure(owner)(member.tpe) + member.locationString)
+ )
+
+ // the parameter symbols need to have the new owner
+ bridge setInfo (otpe cloneInfo bridge)
+ bridgeTarget(bridge) = member
+ afterErasure(owner.info.decls enter bridge)
+ if (other.owner == owner) {
+ afterErasure(owner.info.decls.unlink(other))
+ toBeRemoved += other
+ }
+ bridgesScope enter bridge
+ bridges ::= makeBridgeDefDef(bridge, member, other)
+ }
+
+ def makeBridgeDefDef(bridge: Symbol, member: Symbol, other: Symbol) = afterErasure {
+ // type checking ensures we can safely call `other`, but unless `member.tpe <:< other.tpe`,
+ // calling `member` is not guaranteed to succeed in general, there's
+ // nothing we can do about this, except for an unapply: when this subtype test fails,
+ // return None without calling `member`
+ //
+ // TODO: should we do this for user-defined unapplies as well?
+ // does the first argument list have exactly one argument -- for user-defined unapplies we can't be sure
+ def maybeWrap(bridgingCall: Tree): Tree = {
+ val canReturnNone = afterErasure(
+ member.isSynthetic
+ && (member.name == nme.unapply || member.name == nme.unapplySeq)
+ && !(member.tpe <:< other.tpe) // no static guarantees (TODO: is the subtype test ever true?)
+ )
+ if (canReturnNone) {
+ import CODE._
+ val typeTest = gen.mkIsInstanceOf(REF(bridge.firstParam), member.tpe.params.head.tpe)
+ IF (typeTest) THEN bridgingCall ELSE REF(NoneModule)
+ }
+ else bridgingCall
+ }
+ val rhs = member.tpe match {
+ case MethodType(Nil, ConstantType(c)) => Literal(c)
+ case _ =>
+ val sel: Tree = Select(This(owner), member)
+ val bridgingCall = (sel /: bridge.paramss)((fun, vparams) => Apply(fun, vparams map Ident))
+
+ maybeWrap(bridgingCall)
+ }
+ atPos(bridge.pos)(DefDef(bridge, rhs))
+ }
+ }
+
/** The modifier typer which retypes with erased types. */
class Eraser(_context: Context) extends Typer(_context) {
@@ -790,93 +887,10 @@ abstract class Erasure extends AddInterfaces
* type of `m1` in the template.
*/
private def bridgeDefs(owner: Symbol): (List[Tree], immutable.Set[Symbol]) = {
- var toBeRemoved: immutable.Set[Symbol] = immutable.Set()
- debuglog("computing bridges for " + owner)//DEBUG
assert(phase == currentRun.erasurePhase, phase)
- val site = owner.thisType
- val bridgesScope = newScope
- val bridgeTarget = new mutable.HashMap[Symbol, Symbol]
- var bridges: List[Tree] = List()
- val opc = beforeExplicitOuter {
- new overridingPairs.Cursor(owner) {
- override def parents: List[Type] = List(owner.info.firstParent)
- override def exclude(sym: Symbol): Boolean =
- !sym.isMethod || sym.isPrivate || super.exclude(sym)
- }
- }
- while (opc.hasNext) {
- val member = opc.overriding
- val other = opc.overridden
- //println("bridge? " + member + ":" + member.tpe + member.locationString + " to " + other + ":" + other.tpe + other.locationString)//DEBUG
- if (beforeExplicitOuter(!member.isDeferred)) {
- val otpe = erasure(owner)(other.tpe)
- val bridgeNeeded = afterErasure (
- !(other.tpe =:= member.tpe) &&
- !(deconstMap(other.tpe) =:= deconstMap(member.tpe)) &&
- { var e = bridgesScope.lookupEntry(member.name)
- while ((e ne null) && !((e.sym.tpe =:= otpe) && (bridgeTarget(e.sym) == member)))
- e = bridgesScope.lookupNextEntry(e)
- (e eq null)
- }
- );
- if (bridgeNeeded) {
- val newFlags = (member.flags | BRIDGE) & ~(ACCESSOR | DEFERRED | LAZY | lateDEFERRED)
- val bridge = other.cloneSymbolImpl(owner, newFlags) setPos owner.pos
- // the parameter symbols need to have the new owner
- bridge.setInfo(otpe.cloneInfo(bridge))
- bridgeTarget(bridge) = member
- afterErasure { owner.info.decls.enter(bridge) }
- if (other.owner == owner) {
- //println("bridge to same: "+other+other.locationString)//DEBUG
- afterErasure { owner.info.decls.unlink(other) }
- toBeRemoved += other
- }
- bridgesScope enter bridge
- bridges =
- afterErasure {
- atPos(bridge.pos) {
- val bridgeDef =
- DefDef(bridge,
- member.tpe match {
- case MethodType(List(), ConstantType(c)) => Literal(c)
- case _ =>
- val bridgingCall = (((Select(This(owner), member): Tree) /: bridge.paramss)
- ((fun, vparams) => Apply(fun, vparams map Ident)))
- // type checking ensures we can safely call `other`, but unless `member.tpe <:< other.tpe`, calling `member` is not guaranteed to succeed
- // in general, there's nothing we can do about this, except for an unapply: when this subtype test fails, return None without calling `member`
- if ( member.isSynthetic // TODO: should we do this for user-defined unapplies as well?
- && ((member.name == nme.unapply) || (member.name == nme.unapplySeq))
- // && (bridge.paramss.nonEmpty && bridge.paramss.head.nonEmpty && bridge.paramss.head.tail.isEmpty) // does the first argument list has exactly one argument -- for user-defined unapplies we can't be sure
- && !(afterErasure(member.tpe <:< other.tpe))) { // no static guarantees (TODO: is the subtype test ever true?)
- import CODE._
- val typeTest = gen.mkIsInstanceOf(REF(bridge.firstParam), member.tpe.params.head.tpe, any = true, wrapInApply = true) // any = true since we're before erasure (?), wrapInapply is true since we're after uncurry
- // println("unapp type test: "+ typeTest)
- IF (typeTest) THEN bridgingCall ELSE REF(NoneModule)
- } else bridgingCall
- });
- debuglog("generating bridge from " + other + "(" + Flags.flagsToString(bridge.flags) + ")" + ":" + otpe + other.locationString + " to " + member + ":" + erasure(owner)(member.tpe) + member.locationString + " =\n " + bridgeDef);
- bridgeDef
- }
- } :: bridges
- }
- }
- opc.next
- }
- (bridges, toBeRemoved)
+ debuglog("computing bridges for " + owner)
+ new ComputeBridges(owner) compute()
}
-/*
- for (bc <- site.baseClasses.tail; other <- bc.info.decls.toList) {
- if (other.isMethod && !other.isConstructor) {
- for (member <- site.nonPrivateMember(other.name).alternatives) {
- if (member != other &&
- !(member hasFlag DEFERRED) &&
- (site.memberType(member) matches site.memberType(other)) &&
- !(site.parents exists (p =>
- (p.symbol isSubClass member.owner) && (p.symbol isSubClass other.owner)))) {
-...
- }
- }
-*/
def addBridges(stats: List[Tree], base: Symbol): List[Tree] =
if (base.isTrait) stats
diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
index 4c3972519a..5104518dd9 100644
--- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
@@ -28,6 +28,9 @@ abstract class ExtensionMethods extends Transform with TypingTransformers {
/** the following two members override abstract members in Transform */
val phaseName: String = "extmethods"
+ /** The following flags may be set by this phase: */
+ override def phaseNewFlags: Long = notPRIVATE
+
def newTransformer(unit: CompilationUnit): Transformer =
new Extender(unit)
@@ -101,6 +104,7 @@ abstract class ExtensionMethods extends Transform with TypingTransformers {
case Template(_, _, _) =>
if (currentOwner.isDerivedValueClass) {
extensionDefs(currentOwner.companionModule) = new mutable.ListBuffer[Tree]
+ currentOwner.primaryConstructor.makeNotPrivate(NoSymbol)
super.transform(tree)
} else if (currentOwner.isStaticOwner) {
super.transform(tree)
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index 639e060812..adbb7d43d0 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -24,7 +24,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
/** This map contains a binding (class -> info) if
* the class with this info at phase mixinPhase has been treated for mixin composition
*/
- private val treatedClassInfos = perRunCaches.newMap[Symbol, Type]()
+ private val treatedClassInfos = perRunCaches.newMap[Symbol, Type]() withDefaultValue NoType
/** Map a lazy, mixedin field accessor to it's trait member accessor */
private val initializer = perRunCaches.newMap[Symbol, Symbol]
@@ -104,7 +104,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
*/
private val toInterfaceMap = new TypeMap {
def apply(tp: Type): Type = mapOver( tp match {
- case TypeRef(pre, sym, args) if (sym.isImplClass) =>
+ case TypeRef(pre, sym, args) if sym.isImplClass =>
typeRef(pre, beforeMixin(sym.toInterface), args)
case _ => tp
})
@@ -113,10 +113,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
/** The implementation class corresponding to a currently compiled interface.
* todo: try to use Symbol.implClass instead?
*/
- private def implClass(iface: Symbol): Symbol = {
- val impl = iface.implClass
- if (impl != NoSymbol) impl else erasure.implClass(iface)
- }
+ private def implClass(iface: Symbol) = iface.implClass orElse (erasure implClass iface)
/** Returns the symbol that is accessed by a super-accessor in a mixin composition.
*
@@ -168,6 +165,29 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
debuglog("new member of " + clazz + ":" + member.defString)
clazz.info.decls enter member setFlag MIXEDIN
}
+ def cloneAndAddMember(mixinClass: Symbol, mixinMember: Symbol, clazz: Symbol): Symbol =
+ addMember(clazz, cloneBeforeErasure(mixinClass, mixinMember, clazz))
+
+ def cloneBeforeErasure(mixinClass: Symbol, mixinMember: Symbol, clazz: Symbol): Symbol = {
+ val newSym = beforeErasure {
+ // since we used `mixinMember` from the interface that represents the trait that's
+ // being mixed in, have to instantiate the interface type params (that may occur in mixinMember's
+ // info) as they are seen from the class. We can't use the member that we get from the
+ // implementation class, as it's a clone that was made after erasure, and thus it does not
+ // know its info at the beginning of erasure anymore.
+ // Optimize: no need if mixinClass has no typeparams.
+ mixinMember cloneSymbol clazz modifyInfo (info =>
+ if (mixinClass.typeParams.isEmpty) info
+ else (clazz.thisType baseType mixinClass) memberInfo mixinMember
+ )
+ }
+ // clone before erasure got rid of type info we'll need to generate a javaSig
+ // now we'll have the type info at (the beginning of) erasure in our history,
+ // and now newSym has the info that's been transformed to fit this period
+ // (no need for asSeenFrom as phase.erasedTypes)
+ // TODO: verify we need the updateInfo and document why
+ newSym updateInfo (mixinMember.info cloneInfo newSym)
+ }
def needsExpandedSetterName(field: Symbol) = !field.isLazy && (
if (field.isMethod) field.hasStableFlag
@@ -181,9 +201,12 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* - lazy fields don't get a setter.
*/
def addLateInterfaceMembers(clazz: Symbol) {
- if ((treatedClassInfos get clazz) != Some(clazz.info)) {
+ def makeConcrete(member: Symbol) =
+ member setPos clazz.pos resetFlag (DEFERRED | lateDEFERRED)
+
+ if (treatedClassInfos(clazz) != clazz.info) {
treatedClassInfos(clazz) = clazz.info
- assert(phase == currentRun.mixinPhase)
+ assert(phase == currentRun.mixinPhase, phase)
/** Create a new getter. Getters are never private or local. They are
* always accessors and deferred. */
@@ -210,8 +233,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
}
clazz.info // make sure info is up to date, so that implClass is set.
- val impl = implClass(clazz)
- assert(impl != NoSymbol)
+ val impl = implClass(clazz) orElse abort("No impl class for " + clazz)
for (member <- impl.info.decls) {
if (!member.isMethod && !member.isModule && !member.isModuleVar) {
@@ -242,139 +264,107 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* - for every super accessor in T, add an implementation of that accessor
* - for every module in T, add a module
*/
- def addMixedinMembers(clazz: Symbol, unit : CompilationUnit) {
- def cloneBeforeErasure(iface: Symbol, clazz: Symbol, imember: Symbol): Symbol = {
- val newSym = beforeErasure {
- val res = imember.cloneSymbol(clazz)
- // since we used the member (imember) from the interface that represents the trait that's being mixed in,
- // have to instantiate the interface type params (that may occur in imember's info) as they are seen from the class
- // we can't use the member that we get from the implementation class, as it's a clone that was made after erasure,
- // and thus it does not know its info at the beginning of erasure anymore
- // optimize: no need if iface has no typeparams
- if(iface.typeParams nonEmpty) res.setInfo(clazz.thisType.baseType(iface).memberInfo(imember))
- res
- } // clone before erasure got rid of type info we'll need to generate a javaSig
- // now we'll have the type info at (the beginning of) erasure in our history,
- newSym.updateInfo(imember.info.cloneInfo(newSym)) // and now newSym has the info that's been transformed to fit this period (no need for asSeenFrom as phase.erasedTypes)
- newSym // TODO: verify we need the updateInfo and document why
- }
-
- if (!(clazz hasFlag JAVA) && (treatedClassInfos get clazz) != Some(clazz.info)) {
- treatedClassInfos(clazz) = clazz.info
-
- assert(!clazz.isTrait, clazz)
- assert(clazz.info.parents.nonEmpty, clazz)
-
- // first complete the superclass with mixed in members
- addMixedinMembers(clazz.superClass, unit)
-
- //Console.println("adding members of " + clazz.info.baseClasses.tail.takeWhile(superclazz !=) + " to " + clazz);//DEBUG
-
- /** Mix in members of implementation class mixinClass into class clazz */
- def mixinImplClassMembers(impl: Symbol, iface: Symbol) {
- assert(
- // XXX this should be impl.isImplClass, except that we get impl classes
- // coming through under -optimise which do not agree that they are (because
- // the IMPLCLASS flag is unset, I believe.) See ticket #4285.
- nme.isImplClassName(impl.name) || impl.isImplClass,
- "%s (%s) is not a an implementation class, it cannot mix in %s".format(
- impl, impl.defaultFlagString, iface)
- )
- if (!impl.isImplClass) {
- debugwarn("!!! " + impl + " has an impl class name, but !isImplClass: " + impl.defaultFlagString + ", mixing in " + iface)
- }
+ def addMixedinMembers(clazz: Symbol, unit: CompilationUnit) {
+ def cloneAndAddMixinMember(mixinClass: Symbol, mixinMember: Symbol): Symbol = (
+ cloneAndAddMember(mixinClass, mixinMember, clazz)
+ setPos clazz.pos
+ resetFlag DEFERRED | lateDEFERRED
+ )
- for (member <- impl.info.decls) {
- if (isForwarded(member)) {
- val imember = member.overriddenSymbol(iface)
- // atPhase(currentRun.erasurePhase){
- // println(""+(clazz, iface, clazz.typeParams, iface.typeParams, imember, clazz.thisType.baseType(iface), clazz.thisType.baseType(iface).memberInfo(imember), imember.info substSym(iface.typeParams, clazz.typeParams) ))
- // }
- // Console.println("mixin member "+member+":"+member.tpe+member.locationString+" "+imember+" "+imember.overridingSymbol(clazz)+" to "+clazz+" with scope "+clazz.info.decls)//DEBUG
- if (imember.overridingSymbol(clazz) == NoSymbol &&
- clazz.info.findMember(member.name, 0, lateDEFERRED, false).alternatives.contains(imember)) {
- val member1 = addMember(
- clazz,
- cloneBeforeErasure(iface, clazz, imember) setPos clazz.pos resetFlag (DEFERRED | lateDEFERRED))
- member1.asInstanceOf[TermSymbol] setAlias member;
- }
- }
+ /** Mix in members of implementation class mixinClass into class clazz */
+ def mixinImplClassMembers(mixinClass: Symbol, mixinInterface: Symbol) {
+ assert(mixinClass.isImplClass, "Not an impl class:" +
+ ((mixinClass.debugLocationString, mixinInterface.debugLocationString)))
+
+ for (member <- mixinClass.info.decls ; if isForwarded(member)) {
+ val imember = member overriddenSymbol mixinInterface
+ imember overridingSymbol clazz match {
+ case NoSymbol =>
+ if (clazz.info.findMember(member.name, 0, lateDEFERRED, false).alternatives contains imember)
+ cloneAndAddMixinMember(mixinInterface, imember).asInstanceOf[TermSymbol] setAlias member
+ case _ =>
}
}
+ }
- /** Mix in members of trait mixinClass into class clazz. Also,
- * for each lazy field in mixinClass, add a link from its mixed in member to its
- * initializer method inside the implclass.
- */
- def mixinTraitMembers(mixinClass: Symbol) {
- // For all members of a trait's interface do:
- for (member <- mixinClass.info.decls) {
- if (isConcreteAccessor(member)) {
- if (isOverriddenAccessor(member, clazz.info.baseClasses)) {
- debugwarn("!!! is overridden val: "+member.fullLocationString)
+ /** Mix in members of trait mixinClass into class clazz. Also,
+ * for each lazy field in mixinClass, add a link from its mixed in member to its
+ * initializer method inside the implclass.
+ */
+ def mixinTraitMembers(mixinClass: Symbol) {
+ // For all members of a trait's interface do:
+ for (mixinMember <- mixinClass.info.decls) {
+ if (isConcreteAccessor(mixinMember)) {
+ if (isOverriddenAccessor(mixinMember, clazz.info.baseClasses))
+ debugwarn("!!! is overridden val: "+mixinMember.fullLocationString)
+ else {
+ // mixin field accessors
+ val mixedInAccessor = cloneAndAddMixinMember(mixinClass, mixinMember)
+ if (mixinMember.isLazy) {
+ initializer(mixedInAccessor) = (
+ implClass(mixinClass).info.decl(mixinMember.name)
+ orElse abort("Could not find initializer for " + mixinMember.name)
+ )
}
- else {
- // mixin field accessors
- val member1 = addMember(
- clazz,
- cloneBeforeErasure(mixinClass, clazz, member) //member.cloneSymbol(clazz)
- setPos clazz.pos
- resetFlag (DEFERRED | lateDEFERRED))
- // println("mixing in: "+ (member, member.info, member1.info))
- // atPhase(currentRun.erasurePhase){
- // println("before erasure: "+ (member.info, member1.info))
- // }
- if (member.isLazy) {
- var init = implClass(mixinClass).info.decl(member.name)
- assert(init != NoSymbol, "Could not find initializer for " + member.name)
- initializer(member1) = init
+ if (!mixinMember.isSetter)
+ mixinMember.tpe match {
+ case MethodType(Nil, ConstantType(_)) =>
+ // mixinMember is a constant; only getter is needed
+ ;
+ case MethodType(Nil, TypeRef(_, UnitClass, _)) =>
+ // mixinMember is a value of type unit. No field needed
+ ;
+ case _ => // otherwise mixin a field as well
+ // atPhase: the private field is moved to the implementation class by erasure,
+ // so it can no longer be found in the mixinMember's owner (the trait)
+ val accessed = beforePickler(mixinMember.accessed)
+ // #3857, need to retain info before erasure when cloning (since cloning only
+ // carries over the current entry in the type history)
+ val sym = beforeErasure {
+ // so we have a type history entry before erasure
+ clazz.newValue(nme.getterToLocal(mixinMember.name), mixinMember.pos).setInfo(mixinMember.tpe.resultType)
+ }
+ sym updateInfo mixinMember.tpe.resultType // info at current phase
+
+ val newFlags = (
+ ( PrivateLocal )
+ | ( mixinMember getFlag MUTABLE | LAZY)
+ | ( if (mixinMember.hasStableFlag) 0 else MUTABLE )
+ )
+
+ addMember(clazz, sym setFlag newFlags setAnnotations accessed.annotations)
}
- if (!member.isSetter)
- member.tpe match {
- case MethodType(Nil, ConstantType(_)) =>
- // member is a constant; only getter is needed
- ;
- case MethodType(Nil, TypeRef(_, UnitClass, _)) =>
- // member is a value of type unit. No field needed
- ;
- case _ => // otherwise mixin a field as well
- // atPhase: the private field is moved to the implementation class by erasure,
- // so it can no longer be found in the member's owner (the trait)
- val accessed = beforePickler(member.accessed)
- val sym = beforeErasure { // #3857, need to retain info before erasure when cloning (since cloning only carries over the current entry in the type history)
- clazz.newValue(nme.getterToLocal(member.name), member.pos).setInfo(member.tpe.resultType) // so we have a type history entry before erasure
- }
- sym.updateInfo(member.tpe.resultType) // info at current phase
- addMember(clazz,
- sym
- setFlag (PrivateLocal | member.getFlag(MUTABLE | LAZY))
- setFlag (if (!member.hasStableFlag) MUTABLE else 0)
- setAnnotations accessed.annotations)
- }
- }
- }
- else if (member.isSuperAccessor) { // mixin super accessors
- val member1 = addMember(clazz, member.cloneSymbol(clazz)) setPos clazz.pos
- assert(member1.alias != NoSymbol, member1)
- val alias1 = rebindSuper(clazz, member.alias, mixinClass)
- member1.asInstanceOf[TermSymbol] setAlias alias1
-
- }
- else if (member.isMethod && member.isModule && member.hasNoFlags(LIFTED | BRIDGE)) {
- // mixin objects: todo what happens with abstract objects?
- addMember(clazz, member.cloneSymbol(clazz, member.flags & ~(DEFERRED | lateDEFERRED)) setPos clazz.pos)
}
}
+ else if (mixinMember.isSuperAccessor) { // mixin super accessors
+ val superAccessor = addMember(clazz, mixinMember.cloneSymbol(clazz)) setPos clazz.pos
+ assert(superAccessor.alias != NoSymbol, superAccessor)
+ val alias1 = rebindSuper(clazz, mixinMember.alias, mixinClass)
+ superAccessor.asInstanceOf[TermSymbol] setAlias alias1
+ }
+ else if (mixinMember.isMethod && mixinMember.isModule && mixinMember.hasNoFlags(LIFTED | BRIDGE)) {
+ // mixin objects: todo what happens with abstract objects?
+ addMember(clazz, mixinMember.cloneSymbol(clazz, mixinMember.flags & ~(DEFERRED | lateDEFERRED)) setPos clazz.pos)
+ }
}
+ }
- for (mc <- clazz.mixinClasses)
- if (mc hasFlag lateINTERFACE) {
- // @SEAN: adding trait tracking so we don't have to recompile transitive closures
- unit.depends += mc
- addLateInterfaceMembers(mc)
- mixinTraitMembers(mc)
- mixinImplClassMembers(implClass(mc), mc)
- }
+ if (clazz.isJavaDefined || treatedClassInfos(clazz) == clazz.info)
+ return
+
+ treatedClassInfos(clazz) = clazz.info
+ assert(!clazz.isTrait && clazz.info.parents.nonEmpty, clazz)
+
+ // first complete the superclass with mixed in members
+ addMixedinMembers(clazz.superClass, unit)
+
+ //Console.println("adding members of " + clazz.info.baseClasses.tail.takeWhile(superclazz !=) + " to " + clazz);//DEBUG
+ for (mc <- clazz.mixinClasses ; if mc hasFlag lateINTERFACE) {
+ // @SEAN: adding trait tracking so we don't have to recompile transitive closures
+ unit.depends += mc
+ addLateInterfaceMembers(mc)
+ mixinTraitMembers(mc)
+ mixinImplClassMembers(implClass(mc), mc)
}
}
@@ -436,9 +426,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* Such fields will be nulled after the initializer has memoized the lazy value.
*/
def singleUseFields(templ: Template): collection.Map[Symbol, List[Symbol]] = {
- val usedIn = new mutable.HashMap[Symbol, List[Symbol]] {
- override def default(key: Symbol) = Nil
- }
+ val usedIn = mutable.HashMap[Symbol, List[Symbol]]() withDefaultValue Nil
object SingleUseTraverser extends Traverser {
override def traverse(tree: Tree) {
@@ -477,7 +465,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
new MixinTransformer(unit)
class MixinTransformer(unit : CompilationUnit) extends Transformer {
-
/** Within a static implementation method: the parameter referring to the
* current object. Undefined everywhere else.
*/
@@ -1129,18 +1116,20 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* - refer to fields in some implementation class via an abstract method in the interface.
*/
private def postTransform(tree: Tree): Tree = {
+ def siteWithinImplClass = currentOwner.enclClass.isImplClass
val sym = tree.symbol
+
// change every node type that refers to an implementation class to its
// corresponding interface, unless the node's symbol is an implementation class.
if (tree.tpe.typeSymbol.isImplClass && ((sym eq null) || !sym.isImplClass))
tree.tpe = toInterface(tree.tpe)
tree match {
- case Template(parents, self, body) =>
+ case templ @ Template(parents, self, body) =>
// change parents of templates to conform to parents in the symbol info
val parents1 = currentOwner.info.parents map (t => TypeTree(t) setPos tree.pos)
// mark fields which can be nulled afterward
- lazyValNullables = nullableFields(tree.asInstanceOf[Template]) withDefaultValue Set()
+ lazyValNullables = nullableFields(templ) withDefaultValue Set()
// add all new definitions to current class or interface
treeCopy.Template(tree, parents1, self, addNewDefs(currentOwner, body))
@@ -1179,18 +1168,23 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
// - if `m` refers to a trait, insert a static call to the corresponding static
// implementation
// - otherwise return tree unchanged
- if (mix == tpnme.EMPTY && currentOwner.enclClass.isImplClass)
- assert(false, "illegal super in trait: " + currentOwner.enclClass + " " + tree);
+ assert(
+ !(mix == tpnme.EMPTY && siteWithinImplClass),
+ "illegal super in trait: " + currentOwner.enclClass + " " + tree
+ )
+
if (sym.owner hasFlag lateINTERFACE) {
if (sym.hasAccessorFlag) {
assert(args.isEmpty, args)
val sym1 = sym.overridingSymbol(currentOwner.enclClass)
typedPos(tree.pos)((transformSuper(qual) DOT sym1)())
- } else {
+ }
+ else {
staticCall(beforePrevPhase(sym.overridingSymbol(implClass(sym.owner))))
}
- } else {
- assert(!currentOwner.enclClass.isImplClass, currentOwner.enclClass)
+ }
+ else {
+ assert(!siteWithinImplClass, currentOwner.enclClass)
tree
}
case _ =>
@@ -1208,8 +1202,8 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
// refer to fields in some implementation class via an abstract
// getter in the interface.
val iface = toInterface(sym.owner.tpe).typeSymbol
- val getter = sym.getter(iface)
- assert(getter != NoSymbol, sym)
+ val getter = sym getter iface orElse abort("No getter for " + sym + " in " + iface)
+
typedPos(tree.pos)((qual DOT getter)())
case Assign(Apply(lhs @ Select(qual, _), List()), rhs) =>
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index 7b0f5254b6..1afa1dbf58 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -134,16 +134,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
case _ => false
}
- def unspecializedSymbol(sym: Symbol): Symbol = {
- if (sym hasFlag SPECIALIZED) {
- // add initialization from its generic class constructor
- val genericName = nme.unspecializedName(sym.name)
- val member = sym.owner.info.decl(genericName.toTypeName)
- member
- }
- else NoSymbol
- }
-
object TypeEnv {
/** Return a new type environment binding specialized type parameters of sym to
* the given args. Expects the lists to have the same length.
@@ -318,7 +308,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
else specializedTypeVars(sym).intersect(env.keySet)
)
val (methparams, others) = tvars.toList sortBy ("" + _.name) partition (_.owner.isMethod)
- debuglog("specName(" + sym + ") env: " + env + " tvars: " + tvars)
+ // debuglog("specName(" + sym + ") env: " + env + " tvars: " + tvars)
specializedName(sym.name, methparams map env, others map env)
}
@@ -518,7 +508,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
// better evaluate it before creating the new class symbol
val clazzName = specializedName(clazz, env0).toTypeName
val bytecodeClazz = clazz.owner.info.decl(clazzName)
- debuglog("Specializing " + clazz + " found " + bytecodeClazz + " already there")
+ // debuglog("Specializing " + clazz + ", but found " + bytecodeClazz + " already there")
bytecodeClazz.info
val sClass = clazz.owner.newClass(clazzName, clazz.pos, (clazz.flags | SPECIALIZED) & ~CASE)
@@ -574,7 +564,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
parents = parents.head.parents.head :: parents
val extraSpecializedMixins = specializedParents(clazz.info.parents map applyContext)
if (extraSpecializedMixins.nonEmpty)
- debuglog("specializeClass on " + clazz + " founds extra specialized mixins: " + extraSpecializedMixins.mkString(", "))
+ debuglog("extra specialized mixins for %s: %s".format(clazz.name.decode, extraSpecializedMixins.mkString(", ")))
// If the class being specialized has a self-type, the self type may
// require specialization. First exclude classes whose self types have
// the same type constructor as the class itself, since they will
@@ -652,7 +642,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
val NormalizedMember(original) = info(m)
if (nonConflicting(env ++ typeEnv(m))) {
if (info(m).degenerate) {
- debuglog("degenerate normalized member " + m + " info(m): " + info(m))
+ debuglog("degenerate normalized member " + m.defString)
val specMember = enterMember(cloneInSpecializedClass(m, _ & ~DEFERRED))
info(specMember) = Implementation(original)
@@ -660,7 +650,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
}
else debuglog({
val om = forwardToOverload(m)
- "normalizedMember " + m + " om: " + om + " typeEnv(om): " + typeEnv(om)
+ "normalizedMember " + m + " om: " + om + " " + pp(typeEnv(om))
})
}
else
@@ -668,7 +658,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
}
else if (m.isDeferred) { // abstract methods
val specMember = enterMember(cloneInSpecializedClass(m, _ | DEFERRED))
- debuglog("deferred " + specMember.fullName + " remains abstract")
+ // debuglog("deferred " + specMember.fullName + " remains abstract")
info(specMember) = new Abstract(specMember)
// was: new Forward(specMember) {
@@ -698,20 +688,21 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
enterMember(specVal)
// create accessors
- debuglog("m: " + m + " isLocal: " + nme.isLocalName(m.name) + " specVal: " + specVal.name + " isLocal: " + nme.isLocalName(specVal.name))
+ // debuglog("m: " + m + " isLocal: " + nme.isLocalName(m.name) + " specVal: " + specVal.name + " isLocal: " + nme.isLocalName(specVal.name))
+
if (nme.isLocalName(m.name)) {
val specGetter = mkAccessor(specVal, nme.localToGetter(specVal.name)) setInfo MethodType(Nil, specVal.info)
val origGetter = overrideIn(sClass, m.getter(clazz))
info(origGetter) = Forward(specGetter)
enterMember(specGetter)
enterMember(origGetter)
- debuglog("created accessors: " + specGetter + " orig: " + origGetter)
+ debuglog("specialize accessor in %s: %s -> %s".format(sClass.name.decode, origGetter.name.decode, specGetter.name.decode))
clazz.caseFieldAccessors.find(_.name.startsWith(m.name)) foreach { cfa =>
val cfaGetter = overrideIn(sClass, cfa)
info(cfaGetter) = SpecializedAccessor(specVal)
enterMember(cfaGetter)
- debuglog("found case field accessor for " + m + " added override " + cfaGetter);
+ debuglog("override case field accessor %s -> %s".format(m.name.decode, cfaGetter.name.decode))
}
if (specVal.isVariable && m.setter(clazz) != NoSymbol) {
@@ -724,11 +715,15 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
enterMember(specSetter)
enterMember(origSetter)
}
- } else { // if there are no accessors, specialized methods will need to access this field in specialized subclasses
+ }
+ else { // if there are no accessors, specialized methods will need to access this field in specialized subclasses
m.resetFlag(PRIVATE)
specVal.resetFlag(PRIVATE)
+ debuglog("no accessors for %s/%s, specialized methods must access field in subclass".format(
+ m.name.decode, specVal.name.decode))
}
- } else if (m.isClass) {
+ }
+ else if (m.isClass) {
val specClass: Symbol = cloneInSpecializedClass(m, x => x)
typeEnv(specClass) = fullEnv
specClass.name = specializedName(specClass, fullEnv).toTypeName
@@ -787,10 +782,10 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
* // etc.
*/
private def normalizeMember(owner: Symbol, sym: Symbol, outerEnv: TypeEnv): List[Symbol] = {
- debuglog("normalizeMember: " + sym.fullName)
sym :: (
if (!sym.isMethod || beforeTyper(sym.typeParams.isEmpty)) Nil
else {
+ // debuglog("normalizeMember: " + sym.fullNameAsName('.').decode)
var specializingOn = specializedParams(sym)
val unusedStvars = specializingOn filterNot specializedTypeVars(sym.info)
@@ -810,7 +805,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
val (keys, vals) = env.toList.unzip
specMember.name = specializedName(sym, env)
- debuglog("normalizing: " + sym + " to " + specMember + " with params " + tps)
+ // debuglog("%s normalizes to %s%s".format(sym, specMember,
+ // if (tps.isEmpty) "" else " with params " + tps.mkString(", ")))
typeEnv(specMember) = outerEnv ++ env
val tps1 = produceTypeParameters(tps, specMember, env)
@@ -820,11 +816,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
val methodType = sym.info.resultType.instantiateTypeParams(keys ++ tps, vals ++ tps1.map(_.tpe)).cloneInfo(specMember)
specMember setInfo GenPolyType(tps1, methodType)
- debuglog("expanded member: " + sym + ": " + sym.info +
- " -> " + specMember +
- ": " + specMember.info +
- " env: " + env
- )
+ debuglog("%s expands to %s in %s".format(sym, specMember.name.decode, pp(env)))
info(specMember) = NormalizedMember(sym)
overloads(sym) ::= Overload(specMember, env)
specMember
@@ -833,6 +825,17 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
)
}
+ // concise printing of type env
+ private def pp(env: TypeEnv): String = {
+ env.toList.sortBy(_._1.name.toString) map {
+ case (k, v) =>
+ val vsym = v.typeSymbol
+ if (k == vsym) "" + k.name
+ else k.name + ":" + vsym.name
+
+ } mkString ("env(", ", ", ")")
+ }
+
/** Specialize member `m` w.r.t. to the outer environment and the type
* parameters of the innermost enclosing class.
*
@@ -841,37 +844,38 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
* Return a list of symbols that are specializations of 'sym', owned by 'owner'.
*/
private def specializeMember(owner: Symbol, sym: Symbol, outerEnv: TypeEnv, tps: List[Symbol]): List[Symbol] = {
- def specializeOn(tparams: List[Symbol]): List[Symbol] =
- for (spec0 <- specializations(tparams)) yield {
- val spec = mapAnyRefsInOrigCls(spec0, owner)
- if (sym.isPrivate/* || sym.isProtected*/) {
- //sym.privateWithin = sym.enclosingPackage
- sym.resetFlag(PRIVATE).setFlag(PROTECTED)
- debuglog("-->d SETTING PRIVATE WITHIN TO " + sym.enclosingPackage + " for " + sym)
- }
+ def specializeOn(tparams: List[Symbol]): List[Symbol] = specializations(tparams) map { spec0 =>
+ val spec = mapAnyRefsInOrigCls(spec0, owner)
+ if (sym.isPrivate) {
+ sym.resetFlag(PRIVATE).setFlag(PROTECTED)
+ debuglog("Set %s to private[%s]".format(sym, sym.enclosingPackage))
+ }
- val specMember = subst(outerEnv)(specializedOverload(owner, sym, spec))
- typeEnv(specMember) = typeEnv(sym) ++ outerEnv ++ spec
- wasSpecializedForTypeVars(specMember) ++= spec collect { case (s, tp) if s.tpe == tp => s }
+ val specMember = subst(outerEnv)(specializedOverload(owner, sym, spec))
+ typeEnv(specMember) = typeEnv(sym) ++ outerEnv ++ spec
+ wasSpecializedForTypeVars(specMember) ++= spec collect { case (s, tp) if s.tpe == tp => s }
- debuglog("sym " + specMember + " was specialized for type vars " + wasSpecializedForTypeVars(specMember))
- debuglog("added specialized overload: %s in env: %s".format(specMember, typeEnv(specMember)))
+ val wasSpec = wasSpecializedForTypeVars(specMember)
+ if (wasSpec.nonEmpty)
+ debuglog("specialized overload for %s in %s".format(specMember, pp(typeEnv(specMember))))
- overloads(sym) ::= Overload(specMember, spec)
- specMember
- }
+ overloads(sym) ::= Overload(specMember, spec)
+ info(specMember) = SpecialOverload(sym, typeEnv(specMember))
+
+ specMember
+ }
if (sym.isMethod) {
- debuglog("specializeMember %s with tps: %s stvars(sym): %s".format(sym, tps, specializedTypeVars(sym)))
+ val stvars = specializedTypeVars(sym)
+ if (stvars.nonEmpty)
+ debuglog("specialized %s on %s".format(sym.fullLocationString, stvars.map(_.name).mkString(", ")))
val tps1 = if (sym.isConstructor) tps filter (sym.info.paramTypes contains _) else tps
- val tps2 = tps1 intersect specializedTypeVars(sym).toList
+ val tps2 = tps1 filter stvars
if (!sym.isDeferred)
addConcreteSpecMethod(sym)
- val ms = specializeOn(tps2)
- ms foreach (m => info(m) = SpecialOverload(sym, typeEnv(m)))
- ms
+ specializeOn(tps2)
}
else Nil
}
@@ -894,7 +898,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
*
* this method will return List('apply$mcII$sp')
*/
- private def specialOverrides(clazz: Symbol): List[Symbol] = {
+ private def specialOverrides(clazz: Symbol) = logResultIf[List[Symbol]]("specialOverrides(" + clazz + ")", _.nonEmpty) {
/** Return the overridden symbol in syms that needs a specialized overriding symbol,
* together with its specialization environment. The overridden symbol may not be
* the closest to 'overriding', in a given hierarchy.
@@ -917,24 +921,21 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
}
if (!overriding.isParamAccessor) {
for (overridden <- overriding.allOverriddenSymbols) {
- debuglog(
- "Overridden: " + overridden.fullName +
- ": " + overridden.info +
- "\n by " + overriding.fullName +
- ": " + overriding.info
- )
val stvars = specializedTypeVars(overridden.info)
if (stvars.nonEmpty) {
- debuglog("\t\tspecializedTVars: " + stvars)
+ debuglog("specialized override of %s by %s%s".format(overridden.fullLocationString, overriding.fullLocationString,
+ if (stvars.isEmpty) "" else stvars.map(_.name).mkString("(", ", ", ")")))
+
if (currentRun compiles overriding)
checkOverriddenTParams(overridden)
val env = unify(overridden.info, overriding.info, emptyEnv, false)
def atNext = afterSpecialize(overridden.owner.info.decl(specializedName(overridden, env)))
- debuglog("\t\tenv: " + env + "isValid: " + TypeEnv.isValid(env, overridden) + "found: " + atNext)
- if (TypeEnv.restrict(env, stvars).nonEmpty && TypeEnv.isValid(env, overridden) && atNext != NoSymbol)
+ if (TypeEnv.restrict(env, stvars).nonEmpty && TypeEnv.isValid(env, overridden) && atNext != NoSymbol) {
+ debuglog(" " + pp(env) + " found " + atNext)
return (overridden, env)
+ }
}
}
}
@@ -945,7 +946,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
case (NoSymbol, _) => None
case (overridden, env) =>
val om = specializedOverload(clazz, overridden, env)
- debuglog("Added specialized overload %s for %s in env: %s with type: %s".format(om, overriding.fullName, env, om.info))
+ debuglog("specialized overload %s for %s in %s: %s".format(om, overriding.name.decode, pp(env), om.info))
typeEnv(om) = env
addConcreteSpecMethod(overriding)
info(om) = (
@@ -993,7 +994,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
*/
private def unify(tp1: Type, tp2: Type, env: TypeEnv, strict: Boolean): TypeEnv = (tp1, tp2) match {
case (TypeRef(_, sym1, _), _) if isSpecialized(sym1) =>
- debuglog("Unify - basic case: " + tp1 + ", " + tp2)
+ debuglog("Unify " + tp1 + ", " + tp2)
if (isPrimitiveValueClass(tp2.typeSymbol) || isSpecializedAnyRefSubtype(tp2, sym1))
env + ((sym1, tp2))
else if (isSpecializedAnyRefSubtype(tp2, sym1))
@@ -1003,19 +1004,21 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
else
env
case (TypeRef(_, sym1, args1), TypeRef(_, sym2, args2)) =>
- debuglog("Unify TypeRefs: " + tp1 + " and " + tp2 + " with args " + (args1, args2) + " - ")
+ if (args1.nonEmpty || args2.nonEmpty)
+ debuglog("Unify types " + tp1 + " and " + tp2)
+
if (strict && args1.length != args2.length) unifyError(tp1, tp2)
val e = unify(args1, args2, env, strict)
- debuglog("unified to: " + e)
+ if (e.nonEmpty) debuglog("unified to: " + e)
e
case (TypeRef(_, sym1, _), _) if sym1.isTypeParameterOrSkolem =>
env
case (MethodType(params1, res1), MethodType(params2, res2)) =>
if (strict && params1.length != params2.length) unifyError(tp1, tp2)
- debuglog("Unify MethodTypes: " + tp1 + " and " + tp2)
+ debuglog("Unify methods " + tp1 + " and " + tp2)
unify(res1 :: (params1 map (_.tpe)), res2 :: (params2 map (_.tpe)), env, strict)
case (PolyType(tparams1, res1), PolyType(tparams2, res2)) =>
- debuglog("Unify PolyTypes: " + tp1 + " and " + tp2)
+ debuglog("Unify polytypes " + tp1 + " and " + tp2)
if (strict && tparams1.length != tparams2.length)
unifyError(tp1, tp2)
else
@@ -1123,11 +1126,12 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
if (tparams.isEmpty)
afterSpecialize(parents map (_.typeSymbol.info))
- val parents1 = parents map specializedType
- debuglog("transformInfo %s %s with parents1 %s ph: %s".format(
- if (tparams.nonEmpty) " (poly)" else "",
- clazz, parents1, phase)
- )
+ val parents1 = parents mapConserve specializedType
+ if (parents ne parents1) {
+ debuglog("specialization transforms %s%s parents to %s".format(
+ if (tparams.nonEmpty) "(poly) " else "", clazz, parents1)
+ )
+ }
val newScope = newScopeWith(specializeClass(clazz, typeEnv(clazz)) ++ specialOverrides(clazz): _*)
// If tparams.isEmpty, this is just the ClassInfoType.
GenPolyType(tparams, ClassInfoType(parents1, newScope, clazz))
@@ -1253,7 +1257,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
override def traverse(tree: Tree) = tree match {
case DefDef(_, _, _, vparams :: Nil, _, rhs) =>
if (concreteSpecMethods(tree.symbol) || tree.symbol.isConstructor) {
- debuglog("!!! adding body of a defdef %s, symbol %s: %s".format(tree, tree.symbol, rhs))
+ // debuglog("!!! adding body of a defdef %s, symbol %s: %s".format(tree, tree.symbol, rhs))
body(tree.symbol) = rhs
// body(tree.symbol) = tree // whole method
parameters(tree.symbol) = vparams.map(_.symbol)
@@ -1559,7 +1563,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
val env = typeEnv(symbol)
val boundTvars = env.keySet
val origtparams = source.typeParams.filter(tparam => !boundTvars(tparam) || !isScalaValueType(env(tparam)))
- debuglog("substituting " + origtparams + " for " + symbol.typeParams)
+ if (origtparams.nonEmpty || symbol.typeParams.nonEmpty)
+ debuglog("substituting " + origtparams + " for " + symbol.typeParams)
// skolemize type parameters
val oldtparams = tparams map (_.symbol)
@@ -1656,7 +1661,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
buf +=
ClassDef(specCls, atPos(impl.pos)(Template(parents, emptyValDef, List()))
.setSymbol(specCls.newLocalDummy(sym1.pos))) setPos tree.pos
- debuglog("created synthetic class: " + specCls + " of " + sym1 + " in env: " + env)
+ debuglog("created synthetic class: " + specCls + " of " + sym1 + " in " + pp(env))
}
case _ =>
}
diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
index fdb5c7e52e..9915f7e9fc 100644
--- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala
+++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
@@ -36,6 +36,8 @@ abstract class TailCalls extends Transform {
}
}
+ import gen.hasSynthCaseSymbol
+
/**
* A Tail Call Transformer
*
@@ -87,10 +89,22 @@ abstract class TailCalls extends Transform {
class TailCallElimination(unit: CompilationUnit) extends Transformer {
private val defaultReason = "it contains a recursive call not in tail position"
+ /** Has the label been accessed? Then its symbol is in this set. */
+ private val accessed = new collection.mutable.HashSet[Symbol]()
+ // `accessed` was stored as boolean in the current context -- this is no longer tenable
+ // with jumps to labels in tailpositions now considered in tailposition,
+ // a downstream context may access the label, and the upstream one will be none the wiser
+ // this is necessary because tail-calls may occur in places where syntactically they seem impossible
+ // (since we now consider jumps to labels that are in tailposition, such as matchEnd(x) {x})
+
+
class Context() {
/** The current method */
var method: Symbol = NoSymbol
+ // symbols of label defs in this method that are in tail position
+ var tailLabels: Set[Symbol] = Set()
+
/** The current tail-call label */
var label: Symbol = NoSymbol
@@ -104,24 +118,20 @@ abstract class TailCalls extends Transform {
var failReason = defaultReason
var failPos = method.pos
- /** Has the label been accessed? */
- var accessed = false
-
def this(that: Context) = {
this()
this.method = that.method
this.tparams = that.tparams
this.tailPos = that.tailPos
- this.accessed = that.accessed
this.failPos = that.failPos
this.label = that.label
+ this.tailLabels = that.tailLabels
}
def this(dd: DefDef) {
this()
this.method = dd.symbol
this.tparams = dd.tparams map (_.symbol)
this.tailPos = true
- this.accessed = false
this.failPos = dd.pos
/** Create a new method symbol for the current method and store it in
@@ -141,14 +151,14 @@ abstract class TailCalls extends Transform {
def isEligible = method.isEffectivelyFinal
// @tailrec annotation indicates mandatory transformation
def isMandatory = method.hasAnnotation(TailrecClass) && !forMSIL
- def isTransformed = isEligible && accessed
+ def isTransformed = isEligible && accessed(label)
def tailrecFailure() = unit.error(failPos, "could not optimize @tailrec annotated " + method + ": " + failReason)
def newThis(pos: Position) = method.newValue(nme.THIS, pos, SYNTHETIC) setInfo currentClass.typeOfThis
override def toString(): String = (
"" + method.name + " tparams: " + tparams + " tailPos: " + tailPos +
- " accessed: " + accessed + "\nLabel: " + label + "\nLabel type: " + label.info
+ " Label: " + label + " Label type: " + label.info
)
}
@@ -206,7 +216,7 @@ abstract class TailCalls extends Transform {
def rewriteTailCall(recv: Tree): Tree = {
debuglog("Rewriting tail recursive call: " + fun.pos.lineContent.trim)
- ctx.accessed = true
+ accessed += ctx.label
typedPos(fun.pos)(Apply(Ident(ctx.label), recv :: transformArgs))
}
@@ -242,10 +252,16 @@ abstract class TailCalls extends Transform {
unit.error(tree.pos, "@tailrec annotated method contains no recursive calls")
}
}
- debuglog("Considering " + dd.name + " for tailcalls")
+
+ // labels are local to a method, so only traverse the rhs of a defdef
+ val collectTailPosLabels = new TailPosLabelsTraverser
+ collectTailPosLabels traverse rhs0
+ newCtx.tailLabels = collectTailPosLabels.tailLabels.toSet
+
+ debuglog("Considering " + dd.name + " for tailcalls, with labels in tailpos: "+ newCtx.tailLabels)
val newRHS = transform(rhs0, newCtx)
- deriveDefDef(tree)(rhs =>
+ deriveDefDef(tree){rhs =>
if (newCtx.isTransformed) {
/** We have rewritten the tree, but there may be nested recursive calls remaining.
* If @tailrec is given we need to fail those now.
@@ -270,8 +286,22 @@ abstract class TailCalls extends Transform {
newRHS
}
+ }
+
+ // a translated match
+ case Block(stats, expr) if stats forall hasSynthCaseSymbol =>
+ // the assumption is once we encounter a case, the remainder of the block will consist of cases
+ // the prologue may be empty, usually it is the valdef that stores the scrut
+ val (prologue, cases) = stats span (s => !s.isInstanceOf[LabelDef])
+ treeCopy.Block(tree,
+ noTailTransforms(prologue) ++ transformTrees(cases),
+ transform(expr)
)
+ // a translated casedef
+ case LabelDef(_, _, body) if hasSynthCaseSymbol(tree) =>
+ deriveLabelDef(tree)(transform)
+
case Block(stats, expr) =>
treeCopy.Block(tree,
noTailTransforms(stats),
@@ -308,8 +338,23 @@ abstract class TailCalls extends Transform {
case Apply(fun, args) =>
if (fun.symbol == Boolean_or || fun.symbol == Boolean_and)
treeCopy.Apply(tree, fun, transformTrees(args))
- else
- rewriteApply(fun, fun, Nil, args)
+ else if (fun.symbol.isLabel && args.nonEmpty && args.tail.isEmpty && ctx.tailLabels(fun.symbol)) {
+ // this is to detect tailcalls in translated matches
+ // it's a one-argument call to a label that is in a tailposition and that looks like label(x) {x}
+ // thus, the argument to the call is in tailposition
+ val saved = ctx.tailPos
+ ctx.tailPos = true
+ debuglog("in tailpos label: "+ args.head)
+ val res = transform(args.head)
+ ctx.tailPos = saved
+ if (res ne args.head) {
+ // we tail-called -- TODO: shield from false-positives where we rewrite but don't tail-call
+ // must leave the jump to the original tailpos-label (fun)!
+ // there might be *a* tailcall *in* res, but it doesn't mean res *always* tailcalls
+ treeCopy.Apply(tree, fun, List(res))
+ }
+ else rewriteApply(fun, fun, Nil, args)
+ } else rewriteApply(fun, fun, Nil, args)
case Alternative(_) | Star(_) | Bind(_, _) =>
sys.error("We should've never gotten inside a pattern")
@@ -320,4 +365,66 @@ abstract class TailCalls extends Transform {
}
}
}
+
+ // collect the LabelDefs (generated by the pattern matcher) in a DefDef that are in tail position
+ // the labels all look like: matchEnd(x) {x}
+ // then, in a forward jump `matchEnd(expr)`, `expr` is considered in tail position (and the matchEnd jump is replaced by the jump generated by expr)
+ class TailPosLabelsTraverser extends Traverser {
+ val tailLabels = new collection.mutable.ListBuffer[Symbol]()
+
+ private var maybeTail: Boolean = true // since we start in the rhs of a DefDef
+
+ def traverse(tree: Tree, maybeTailNew: Boolean): Unit = {
+ val saved = maybeTail
+ maybeTail = maybeTailNew
+ try traverse(tree)
+ finally maybeTail = saved
+ }
+
+ def traverseNoTail(tree: Tree) = traverse(tree, false)
+ def traverseTreesNoTail(trees: List[Tree]) = trees foreach traverseNoTail
+
+ override def traverse(tree: Tree) = tree match {
+ case LabelDef(_, List(arg), body@Ident(_)) if arg.symbol == body.symbol => // we're looking for label(x){x} in tail position, since that means `a` is in tail position in a call `label(a)`
+ if (maybeTail) tailLabels += tree.symbol
+
+ // a translated casedef
+ case LabelDef(_, _, body) if hasSynthCaseSymbol(tree) =>
+ traverse(body)
+
+ // a translated match
+ case Block(stats, expr) if stats forall hasSynthCaseSymbol =>
+ // the assumption is once we encounter a case, the remainder of the block will consist of cases
+ // the prologue may be empty, usually it is the valdef that stores the scrut
+ val (prologue, cases) = stats span (s => !s.isInstanceOf[LabelDef])
+ traverseTreesNoTail(prologue) // selector (may be absent)
+ traverseTrees(cases)
+ traverse(expr)
+
+ case CaseDef(pat, guard, body) =>
+ traverse(body)
+
+ case Match(selector, cases) =>
+ traverseNoTail(selector)
+ traverseTrees(cases)
+
+ case dd @ DefDef(_, _, _, _, _, _) => // we are run per-method
+
+ case Block(stats, expr) =>
+ traverseTreesNoTail(stats)
+ traverse(expr)
+
+ case If(cond, thenp, elsep) =>
+ traverse(thenp)
+ traverse(elsep)
+
+ case Try(block, catches, finalizer) =>
+ traverseNoTail(block)
+ traverseTreesNoTail(catches)
+ traverseNoTail(finalizer)
+
+ case EmptyTree | Super(_, _) | This(_) | Select(_, _) | Ident(_) | Literal(_) | Function(_, _) | TypeTree() =>
+ case _ => super.traverse(tree)
+ }
+ }
}
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index ee565530b7..0efdd9ab9f 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -168,7 +168,7 @@ abstract class UnCurry extends InfoTransform
private def nonLocalReturnTry(body: Tree, key: Symbol, meth: Symbol) = {
localTyper typed {
val extpe = nonLocalReturnExceptionType(meth.tpe.finalResultType)
- val ex = meth.newValue(body.pos, nme.ex) setInfo extpe
+ val ex = meth.newValue(nme.ex, body.pos) setInfo extpe
val pat = gen.mkBindForCase(ex, NonLocalReturnControlClass, List(meth.tpe.finalResultType))
val rhs = (
IF ((ex DOT nme.key)() OBJ_EQ Ident(key))
@@ -210,14 +210,15 @@ abstract class UnCurry extends InfoTransform
* body = expr match { case P_i if G_i => E_i }_i=1..n
* to:
*
+ //TODO: correct code template below
* class $anon() extends AbstractPartialFunction[T, R] with Serializable {
- * def apply(x: T): R = (expr: @unchecked) match {
+ * def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = (expr: @unchecked) match {
* case P_1 if G_1 => E_1
* ...
- * case P_n if G_n => true
- * case _ => this.missingCase(expr)
+ * case P_n if G_n => E_n
+ * case _ => default(expr)
* }
- * def _isDefinedAt(x: T): boolean = (x: @unchecked) match {
+ * def isDefinedAt(x: T): boolean = (x: @unchecked) match {
* case P_1 if G_1 => true
* ...
* case P_n if G_n => true
@@ -231,123 +232,107 @@ abstract class UnCurry extends InfoTransform
*
* def isDefinedAtCurrent(x: T): boolean = true
*/
- def transformFunction(fun: Function): Tree = {
- val fun1 = deEta(fun)
- def owner = fun.symbol.owner
- def targs = fun.tpe.typeArgs
- def isPartial = fun.tpe.typeSymbol == PartialFunctionClass
-
- if (fun1 ne fun) fun1
- else {
- val (formals, restpe) = (targs.init, targs.last)
- val anonClass = owner.newAnonymousFunctionClass(fun.pos, inConstructorFlag)
- def parents =
- if (isFunctionType(fun.tpe)) List(abstractFunctionForFunctionType(fun.tpe), SerializableClass.tpe)
- else if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, targs), SerializableClass.tpe)
- else List(ObjectClass.tpe, fun.tpe, SerializableClass.tpe)
-
- anonClass setInfo ClassInfoType(parents, newScope, anonClass)
- val applyMethod = anonClass.newMethod(nme.apply, fun.pos, FINAL)
- applyMethod setInfoAndEnter MethodType(applyMethod newSyntheticValueParams formals, restpe)
- anonClass addAnnotation serialVersionUIDAnnotation
-
- fun.vparams foreach (_.symbol.owner = applyMethod)
- fun.body.changeOwner(fun.symbol -> applyMethod)
-
- def missingCaseCall(scrutinee: Tree): Tree = Apply(Select(This(anonClass), nme.missingCase), List(scrutinee))
-
- def applyMethodDef() = {
- val body = localTyper.typedPos(fun.pos) {
- if (isPartial) gen.mkUncheckedMatch(gen.withDefaultCase(fun.body, missingCaseCall))
- else fun.body
- }
- // Have to repack the type to avoid mismatches when existentials
- // appear in the result - see SI-4869.
- val applyResultType = localTyper.packedType(body, applyMethod)
- DefDef(Modifiers(FINAL), nme.apply, Nil, List(fun.vparams), TypeTree(applyResultType), body) setSymbol applyMethod
- }
- def isDefinedAtMethodDef() = {
- val isDefinedAtName = {
- if (anonClass.info.member(nme._isDefinedAt) != NoSymbol) nme._isDefinedAt
- else nme.isDefinedAt
- }
- val m = anonClass.newMethod(isDefinedAtName, fun.pos, FINAL)
- val params = m newSyntheticValueParams formals
- m setInfoAndEnter MethodType(params, BooleanClass.tpe)
+ def transformFunction(fun: Function): Tree =
+ deEta(fun) match {
+ // nullary or parameterless
+ case fun1 if fun1 ne fun => fun1
+ case _ =>
+ def owner = fun.symbol.owner
+ def targs = fun.tpe.typeArgs
+ def isPartial = fun.tpe.typeSymbol == PartialFunctionClass
+ assert(!(opt.virtPatmat && isPartial)) // empty-selector matches have already been translated into instantiations of anonymous (partial) functions
- val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), params)
- def substTree[T <: Tree](t: T): T = substParam(resetLocalAttrs(t))
+ def parents =
+ if (isFunctionType(fun.tpe)) List(abstractFunctionForFunctionType(fun.tpe), SerializableClass.tpe)
+ else if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, targs), SerializableClass.tpe)
+ else List(ObjectClass.tpe, fun.tpe, SerializableClass.tpe)
- object isDefinedAtTransformer extends gen.MatchMatcher {
- // TODO: optimize duplication, but make sure ValDef's introduced by wrap are treated correctly
- override def caseMatch(orig: Tree, selector: Tree, cases: List[CaseDef], wrap: Tree => Tree): Tree = {
- def transformCase(cdef: CaseDef): CaseDef =
- CaseDef(cdef.pat, cdef.guard, Literal(Constant(true)))
+ val anonClass = owner newAnonymousFunctionClass(fun.pos, inConstructorFlag) addAnnotation serialVersionUIDAnnotation
+ anonClass setInfo ClassInfoType(parents, newScope, anonClass)
- def defaultCase = CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false)))
+ val (formals, restpe) = (targs.init, targs.last)
- val casesNoSynthCatchAll = dropSyntheticCatchAll(cases)
+ def applyMethodDef = {
+ val methSym = anonClass.newMethod(nme.apply, fun.pos, FINAL)
+ methSym setInfoAndEnter MethodType(methSym newSyntheticValueParams formals, restpe)
- gen.mkUncheckedMatch(
- if (casesNoSynthCatchAll exists treeInfo.isDefaultCase) Literal(Constant(true))
- else substTree(wrap(Match(selector, (casesNoSynthCatchAll map transformCase) :+ defaultCase)).duplicate)
- )
- }
+ fun.vparams foreach (_.symbol.owner = methSym)
+ fun.body changeOwner (fun.symbol -> methSym)
- override def caseVirtualizedMatch(orig: Tree, _match: Tree, targs: List[Tree], scrut: Tree, matcher: Tree): Tree = {
- object noOne extends Transformer {
- override val treeCopy = newStrictTreeCopier // must duplicate everything
- val one = _match.tpe member newTermName("one")
- override def transform(tree: Tree): Tree = tree match {
- case Apply(fun, List(a)) if fun.symbol == one =>
- // blow one's argument away since all we want to know is whether the match succeeds or not
- // (the alternative, making `one` CBN, would entail moving away from Option)
- Apply(fun.duplicate, List(gen.mkZeroContravariantAfterTyper(a.tpe)))
- case _ =>
- super.transform(tree)
- }
- }
- substTree(Apply(Apply(TypeApply(Select(_match.duplicate, _match.tpe.member(newTermName("isSuccess"))), targs map (_.duplicate)), List(scrut.duplicate)), List(noOne.transform(matcher))))
+ val body = localTyper.typedPos(fun.pos)(fun.body)
+ val methDef = DefDef(methSym, List(fun.vparams), body)
+
+ // Have to repack the type to avoid mismatches when existentials
+ // appear in the result - see SI-4869.
+ methDef.tpt setType localTyper.packedType(body, methSym)
+ methDef
+ }
+
+ // def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 =
+ def applyOrElseMethodDef = {
+ val methSym = anonClass.newMethod(fun.pos, nme.applyOrElse) setFlag (FINAL | OVERRIDE)
+
+ val List(argtpe) = formals
+ val A1 = methSym newTypeParameter(newTypeName("A1")) setInfo TypeBounds.upper(argtpe)
+ val B1 = methSym newTypeParameter(newTypeName("B1")) setInfo TypeBounds.lower(restpe)
+ val methFormals = List(A1.tpe, functionType(List(A1.tpe), B1.tpe))
+ val params@List(x, default) = methSym newSyntheticValueParams methFormals
+ methSym setInfoAndEnter polyType(List(A1, B1), MethodType(params, B1.tpe))
+
+ val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), List(x))
+ val body = localTyper.typedPos(fun.pos) { import CODE._
+ gen.mkUncheckedMatch(gen.withDefaultCase(substParam(fun.body), scrut => REF(default) APPLY (REF(x))))
}
+ body.changeOwner(fun.symbol -> methSym)
- override def caseVirtualizedMatchOpt(orig: Tree, zero: ValDef, x: ValDef, matchRes: ValDef, keepGoing: ValDef, stats: List[Tree], epilogue: Tree, wrap: Tree => Tree) = {
- object dropMatchResAssign extends Transformer {
- // override val treeCopy = newStrictTreeCopier // will duplicate below
- override def transform(tree: Tree): Tree = tree match {
- // don't compute the result of the match -- remove the block for the RHS (emitted by pmgen.one), except for the assignment to keepGoing
- case gen.VirtualCaseDef(assignKeepGoing, matchRes, zero) if assignKeepGoing.lhs.symbol eq keepGoing.symbol =>
- Block(List(assignKeepGoing), zero)
- case _ =>
- super.transform(tree)
- }
+ val methDef = DefDef(methSym, body)
+
+ // Have to repack the type to avoid mismatches when existentials
+ // appear in the result - see SI-4869.
+ methDef.tpt setType localTyper.packedType(body, methSym)
+ methDef
+ }
+
+ // duplicate before applyOrElseMethodDef is run so we start with the same symbols as applyOrElseMethodDef
+ // otherwise `TreeSymSubstituter(fun.vparams map (_.symbol), params)` won't work as the subst has been run already
+ val bodyForIDA = fun.body.duplicate
+ def isDefinedAtMethodDef = {
+ val methSym = anonClass.newMethod(nme.isDefinedAt, fun.pos, FINAL)
+ val params = methSym newSyntheticValueParams formals
+ methSym setInfoAndEnter MethodType(params, BooleanClass.tpe)
+
+ val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), params)
+ def doSubst(x: Tree) = substParam(resetLocalAttrs(x)) // see pos/t1761 for why `resetLocalAttrs`
+ object isDefinedAtTransformer extends gen.MatchMatcher {
+ // TODO: optimize duplication, but make sure ValDef's introduced by wrap are treated correctly
+ override def caseMatch(orig: Tree, selector: Tree, cases: List[CaseDef], wrap: Tree => Tree): Tree = { import CODE._
+ gen.mkUncheckedMatch(
+ if (cases exists treeInfo.isDefaultCase) TRUE_typed
+ else
+ doSubst(wrap(
+ Match(selector,
+ (cases map (c => deriveCaseDef(c)(x => TRUE_typed))) :+ (
+ DEFAULT ==> FALSE_typed)
+ )))
+ )
}
- val statsNoMatchRes: List[Tree] = stats map (dropMatchResAssign.transform) toList
- val idaBlock = wrap(Block(
- zero ::
- x ::
- /* drop matchRes def */
- keepGoing ::
- statsNoMatchRes,
- NOT(REF(keepGoing.symbol)) // replace `if (keepGoing) throw new MatchError(...) else matchRes` epilogue by `!keepGoing`
- ))
- substTree(idaBlock.duplicate) // duplicate on block as a whole to ensure valdefs are properly cloned and substed
}
- }
+ val body = isDefinedAtTransformer(bodyForIDA)
+ body.changeOwner(fun.symbol -> methSym)
- DefDef(m, isDefinedAtTransformer(fun.body))
- }
+ DefDef(methSym, body)
+ }
- val members =
- if (isPartial) List(applyMethodDef, isDefinedAtMethodDef)
- else List(applyMethodDef)
+ val members =
+ if (isPartial) List(applyOrElseMethodDef, isDefinedAtMethodDef)
+ else List(applyMethodDef)
- localTyper.typedPos(fun.pos) {
- Block(
- List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, fun.pos)),
- Typed(New(anonClass.tpe), TypeTree(fun.tpe)))
+ localTyper.typedPos(fun.pos) {
+ Block(
+ List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, fun.pos)),
+ Typed(New(anonClass.tpe), TypeTree(fun.tpe)))
+ }
}
- }
- }
def transformArgs(pos: Position, fun: Symbol, args: List[Tree], formals: List[Type]) = {
val isJava = fun.isJavaDefined
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index ed9fee986f..49ddb985dc 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -317,7 +317,7 @@ trait ContextErrors {
}
withAddendum(qual.pos)(
if (name == nme.CONSTRUCTOR) target + " does not have a constructor"
- else nameString + " is not a member of " + targetKindString + target + addendum
+ else nameString + " is not a member of " + targetKindString + target.directObjectString + addendum
)
}
issueNormalTypeError(sel, errMsg)
@@ -376,21 +376,16 @@ trait ContextErrors {
setError(tree)
}
- def MissingParameterTypeError(fun: Tree, vparam: ValDef, pt: Type) = {
- def anonMessage = (
- "\nThe argument types of an anonymous function must be fully known. (SLS 8.5)" +
- "\nExpected type was: " + pt.toLongString
- )
-
- val suffix =
- if (!vparam.mods.isSynthetic) ""
- else " for expanded function" + (fun match {
- case Function(_, Match(_, _)) => anonMessage
- case _ => " " + fun
- })
+ def MissingParameterTypeError(fun: Tree, vparam: ValDef, pt: Type) =
+ if (vparam.mods.isSynthetic) fun match {
+ case Function(_, Match(_, _)) => MissingParameterTypeAnonMatchError(vparam, pt)
+ case _ => issueNormalTypeError(vparam, "missing parameter type for expanded function " + fun)
+ } else issueNormalTypeError(vparam, "missing parameter type")
- issueNormalTypeError(vparam, "missing parameter type" + suffix)
- }
+ def MissingParameterTypeAnonMatchError(vparam: Tree, pt: Type) =
+ issueNormalTypeError(vparam, "missing parameter type for expanded function\n"+
+ "The argument types of an anonymous function must be fully known. (SLS 8.5)\n"+
+ "Expected type was: " + pt.toLongString)
def ConstructorsOrderError(tree: Tree) = {
issueNormalTypeError(tree, "called constructor's definition must precede calling constructor's definition")
@@ -682,9 +677,9 @@ trait ContextErrors {
def AccessError(tree: Tree, sym: Symbol, pre: Type, owner0: Symbol, explanation: String) = {
def errMsg = {
- val location = if (sym.isClassConstructor) owner0 else pre.widen
+ val location = if (sym.isClassConstructor) owner0 else pre.widen.directObjectString
- underlying(sym).fullLocationString + " cannot be accessed in " +
+ underlyingSymbol(sym).fullLocationString + " cannot be accessed in " +
location + explanation
}
NormalTypeError(tree, errMsg, ErrorKinds.Access)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala
index 29831c8469..f6d1e42c32 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala
@@ -79,7 +79,17 @@ abstract class Duplicators extends Analyzer {
override def mapOver(tpe: Type): Type = tpe match {
case TypeRef(NoPrefix, sym, args) if sym.isTypeParameterOrSkolem =>
- val sym1 = context.scope.lookup(sym.name)
+ var sym1 = context.scope.lookup(sym.name)
+ if (sym1 eq NoSymbol) {
+ // try harder (look in outer scopes)
+ // with virtpatmat, this can happen when the sym is referenced in the scope of a LabelDef but is defined in the scope of an outer DefDef (e.g., in AbstractPartialFunction's andThen)
+ BodyDuplicator.super.silent(_.typedType(Ident(sym.name))) match {
+ case SilentResultValue(t) =>
+ sym1 = t.symbol
+ debuglog("fixed by trying harder: "+(sym, sym1, context))
+ case _ =>
+ }
+ }
// assert(sym1 ne NoSymbol, tpe)
if ((sym1 ne NoSymbol) && (sym1 ne sym)) {
debuglog("fixing " + sym + " -> " + sym1)
@@ -255,9 +265,21 @@ abstract class Duplicators extends Analyzer {
case ldef @ LabelDef(name, params, rhs) =>
// log("label def: " + ldef)
+ // in case the rhs contains any definitions -- TODO: is this necessary?
+ invalidate(rhs)
ldef.tpe = null
- val params1 = params map (p => Ident(updateSym(p.symbol)))
- super.typed(treeCopy.LabelDef(tree, name, params1, rhs), mode, pt)
+
+ // since typer does not create the symbols for a LabelDef's params,
+ // we do that manually here -- we should really refactor LabelDef to be a subclass of DefDef
+ def newParam(p: Tree): Ident = {
+ val newsym = p.symbol.cloneSymbol //(context.owner) // TODO owner?
+ Ident(newsym.setInfo(fixType(p.symbol.info)))
+ }
+ val params1 = params map newParam
+ val rhs1 = (new TreeSubstituter(params map (_.symbol), params1) transform rhs) // TODO: duplicate?
+ rhs1.tpe = null
+
+ super.typed(treeCopy.LabelDef(tree, name, params1, rhs1), mode, pt)
case Bind(name, _) =>
// log("bind: " + tree)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 8b3bc253fd..a1ca4904f4 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -196,10 +196,12 @@ trait Infer {
/* -- Error Messages --------------------------------------------------- */
def setError[T <: Tree](tree: T): T = {
- if (settings.debug.value) { // DEBUG
- println("set error: "+tree);
- throw new Error()
- }
+ debuglog("set error: "+ tree)
+ // this breaks -Ydebug pretty radically
+ // if (settings.debug.value) { // DEBUG
+ // println("set error: "+tree);
+ // throw new Error()
+ // }
def name = newTermName("<error: " + tree.symbol + ">")
def errorClass = if (context.reportErrors) context.owner.newErrorClass(name.toTypeName) else stdErrorClass
def errorValue = if (context.reportErrors) context.owner.newErrorValue(name) else stdErrorValue
@@ -1099,7 +1101,7 @@ trait Infer {
// since instantiateTypeVar wants to modify the skolem that corresponds to the method's type parameter,
// and it uses the TypeVar's origin to locate it, deskolemize the existential skolem to the method tparam skolem
// (the existential skolem was created by adaptConstrPattern to introduce the type slack necessary to soundly deal with variant type parameters)
- case skolem if skolem.isExistentialSkolem => freshVar(skolem.deSkolemize.asInstanceOf[TypeSymbol])
+ case skolem if skolem.isGADTSkolem => freshVar(skolem.deSkolemize.asInstanceOf[TypeSymbol])
case p => freshVar(p)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
index f32ad9293c..b57f139074 100644
--- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
@@ -169,6 +169,16 @@ trait MethodSynthesis {
self: Namer =>
import NamerErrorGen._
+
+ /** TODO - synthesize method.
+ */
+ def enterImplicitClass(tree: ClassDef) {
+ /** e.g.
+ val ClassDef(mods, name, tparams, impl) = tree
+ val converter = ImplicitClassConverter(tree).createAndEnterSymbol()
+ ...
+ */
+ }
def enterGetterSetter(tree: ValDef) {
val ValDef(mods, name, _, _) = tree
@@ -195,17 +205,13 @@ trait MethodSynthesis {
enterBeans(tree)
}
def finishGetterSetter(typer: Typer, stat: Tree): List[Tree] = stat match {
- case vd @ ValDef(mods, name, tpt, rhs) if !noFinishGetterSetter(vd) =>
+ case vd @ ValDef(mods, name, tpt, rhs) if !noFinishGetterSetter(vd) && !vd.symbol.isLazy =>
// If we don't save the annotations, they seem to wander off.
val annotations = stat.symbol.initialize.annotations
- val trees = (
- allValDefDerived(vd)
- map (acc => atPos(vd.pos.focus)(acc derive annotations))
- filterNot (_ eq EmptyTree)
+ ( allValDefDerived(vd)
+ map (acc => atPos(vd.pos.focus)(acc derive annotations))
+ filterNot (_ eq EmptyTree)
)
- // log(trees.mkString("Accessor trees:\n ", "\n ", "\n"))
- if (vd.symbol.isLazy) List(stat)
- else trees
case _ =>
List(stat)
}
@@ -230,14 +236,33 @@ trait MethodSynthesis {
}
trait Derived {
+ /** The tree from which we are deriving a synthetic member. */
+ def tree: Tree
def name: TermName
def flagsMask: Long
def flagsExtra: Long
+
+ /** The tree, symbol, and type completer for the synthetic member. */
def completer(sym: Symbol): Type
+ def derivedSym: Symbol
+ def derivedTree: Tree
}
- trait DerivedFromValDef extends Derived {
- /** The declaration from which we are deriving.
- */
+
+ trait DerivedFromMemberDef extends Derived {
+ def tree: MemberDef
+
+ // Final methods to make the rest easier to reason about.
+ final def mods = tree.mods
+ final def basisSym = tree.symbol
+ final def enclClass = basisSym.enclClass
+ final def derivedFlags: Long = basisSym.flags & flagsMask | flagsExtra
+ }
+
+ trait DerivedFromClassDef extends DerivedFromMemberDef {
+ def tree: ClassDef
+ }
+
+ trait DerivedFromValDef extends DerivedFromMemberDef {
def tree: ValDef
/** Which meta-annotation is associated with this kind of entity.
@@ -245,14 +270,8 @@ trait MethodSynthesis {
*/
def category: Symbol
- // Final methods to make the rest easier to reason about.
- final def mods = tree.mods
- final def basisSym = tree.symbol
- final def enclClass = basisSym.enclClass
-
final def completer(sym: Symbol) = namerOf(sym).accessorTypeCompleter(tree, isSetter)
final def fieldSelection = Select(This(enclClass), basisSym)
- final def derivedFlags: Long = basisSym.flags & flagsMask | flagsExtra
final def derivedMods: Modifiers = mods & flagsMask | flagsExtra mapAnnotations (_ => Nil)
def derivedSym: Symbol = tree.symbol
@@ -312,6 +331,19 @@ trait MethodSynthesis {
private def setterDef = DefDef(derivedSym, setterRhs)
override def derivedTree: Tree = if (setterParam == NoSymbol) EmptyTree else setterDef
}
+
+ /** A synthetic method which performs the implicit conversion implied by
+ * the declaration of an implicit class. Yet to be written.
+ */
+ case class ImplicitClassConverter(tree: ClassDef) extends DerivedFromClassDef {
+ def completer(sym: Symbol): Type = ???
+ def derivedSym: Symbol = ???
+ def derivedTree: DefDef = ???
+ def flagsExtra: Long = ???
+ def flagsMask: Long = ???
+ def name: TermName = ???
+ }
+
case class Getter(tree: ValDef) extends DerivedGetter {
def name = tree.name
def category = GetterTargetClass
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index c5fb13a5a9..8604366bf2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -315,9 +315,10 @@ trait Namers extends MethodSynthesis {
case DefDef(_, _, _, _, _, _) => owner.newMethod(name.toTermName, pos, flags)
case ClassDef(_, _, _, _) => owner.newClassSymbol(name.toTypeName, pos, flags)
case ModuleDef(_, _, _) => owner.newModule(name, pos, flags)
- case ValDef(_, _, _, _) if isParameter => owner.newValueParameter(name, pos, flags)
case PackageDef(pid, _) => createPackageSymbol(pos, pid)
- case ValDef(_, _, _, _) => owner.newValue(name, pos, flags)
+ case ValDef(_, _, _, _) =>
+ if (isParameter) owner.newValueParameter(name, pos, flags)
+ else owner.newValue(name, pos, flags)
}
}
private def createFieldSymbol(tree: ValDef): TermSymbol =
@@ -665,6 +666,10 @@ trait Namers extends MethodSynthesis {
"If possible, define " + tree.symbol + " in " + owner.skipPackageObject + " instead."
)
}
+
+ // Suggested location only.
+ if (mods.isImplicit)
+ enterImplicitClass(tree)
}
// this logic is needed in case typer was interrupted half
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala
index b060fd7121..aff8368f75 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala
@@ -32,6 +32,8 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
import global._
import definitions._
+ val SYNTH_CASE = Flags.CASE | SYNTHETIC
+
object vpmName {
val one = newTermName("one")
val drop = newTermName("drop")
@@ -43,13 +45,13 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
val outer = newTermName("<outer>")
val runOrElse = newTermName("runOrElse")
val zero = newTermName("zero")
- val _match = newTermName("__match") // don't call it __match, since that will trigger virtual pattern matching...
+ val _match = newTermName("__match") // don't call it __match, since that will trigger virtual pattern matching...
def counted(str: String, i: Int) = newTermName(str+i)
}
object MatchTranslator {
- def apply(typer: Typer): MatchTranslation = {
+ def apply(typer: Typer): MatchTranslation with CodegenCore = {
import typer._
// typing `_match` to decide which MatchTranslator to create adds 4% to quick.comp.timer
newTyper(context.makeImplicit(reportAmbiguousErrors = false)).silent(_.typed(Ident(vpmName._match), EXPRmode, WildcardType), reportAmbiguousErrors = false) match {
@@ -116,10 +118,6 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
trait MatchTranslation extends MatchMonadInterface { self: TreeMakers with CodegenCore =>
import typer.{typed, context, silent, reallyExists}
- private def repeatedToSeq(tp: Type): Type = (tp baseType RepeatedParamClass) match {
- case TypeRef(_, RepeatedParamClass, args) => appliedType(SeqClass.typeConstructor, args)
- case _ => tp
- }
/** Implement a pattern match by turning its cases (including the implicit failure case)
* into the corresponding (monadic) extractors, and combining them with the `orElse` combinator.
@@ -131,18 +129,15 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
* thus, you must typecheck the result (and that will in turn translate nested matches)
* this could probably optimized... (but note that the matchStrategy must be solved for each nested patternmatch)
*/
- def translateMatch(scrut: Tree, cases: List[CaseDef], pt: Type): Tree = {
+ def translateMatch(scrut: Tree, cases: List[CaseDef], pt: Type, scrutType: Type, matchFailGenOverride: Option[Tree => Tree] = None): Tree = {
// we don't transform after typers
// (that would require much more sophistication when generating trees,
// and the only place that emits Matches after typers is for exception handling anyway)
assert(phase.id <= currentRun.typerPhase.id, phase)
- val scrutType = repeatedToSeq(elimAnonymousClass(scrut.tpe.widen))
-
- val scrutSym = freshSym(scrut.pos, pureType(scrutType))
- val okPt = repeatedToSeq(pt)
+ val scrutSym = freshSym(scrut.pos, pureType(scrutType)) setFlag SYNTH_CASE
// pt = Any* occurs when compiling test/files/pos/annotDepMethType.scala with -Xexperimental
- combineCases(scrut, scrutSym, cases map translateCase(scrutSym, okPt), okPt, matchOwner)
+ combineCases(scrut, scrutSym, cases map translateCase(scrutSym, pt), pt, matchOwner, matchFailGenOverride)
}
// return list of typed CaseDefs that are supported by the backend (typed/bind/wildcard)
@@ -154,21 +149,22 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
// if they're already simple enough to be handled by the back-end, we're done
if (caseDefs forall treeInfo.isCatchCase) caseDefs
else {
- val okPt = repeatedToSeq(pt)
- val switch = {
+ val swatches = { // switch-catches
val bindersAndCases = caseDefs map { caseDef =>
// generate a fresh symbol for each case, hoping we'll end up emitting a type-switch (we don't have a global scrut there)
// if we fail to emit a fine-grained switch, have to do translateCase again with a single scrutSym (TODO: uniformize substitution on treemakers so we can avoid this)
val caseScrutSym = freshSym(pos, pureType(ThrowableClass.tpe))
- (caseScrutSym, propagateSubstitution(translateCase(caseScrutSym, okPt)(caseDef), EmptySubstitution))
+ (caseScrutSym, propagateSubstitution(translateCase(caseScrutSym, pt)(caseDef), EmptySubstitution))
}
- (emitTypeSwitch(bindersAndCases, pt) map (_.map(fixerUpper(matchOwner, pos).apply(_).asInstanceOf[CaseDef])))
+ for(cases <- emitTypeSwitch(bindersAndCases, pt) toList;
+ if cases forall treeInfo.isCatchCase; // must check again, since it's not guaranteed -- TODO: can we eliminate this? e.g., a type test could test for a trait or a non-trivial prefix, which are not handled by the back-end
+ cse <- cases) yield fixerUpper(matchOwner, pos)(cse).asInstanceOf[CaseDef]
}
- val catches = switch getOrElse {
+ val catches = if (swatches nonEmpty) swatches else {
val scrutSym = freshSym(pos, pureType(ThrowableClass.tpe))
- val casesNoSubstOnly = caseDefs map { caseDef => (propagateSubstitution(translateCase(scrutSym, okPt)(caseDef), EmptySubstitution))}
+ val casesNoSubstOnly = caseDefs map { caseDef => (propagateSubstitution(translateCase(scrutSym, pt)(caseDef), EmptySubstitution))}
val exSym = freshSym(pos, pureType(ThrowableClass.tpe), "ex")
@@ -177,7 +173,7 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
CaseDef(
Bind(exSym, Ident(nme.WILDCARD)), // TODO: does this need fixing upping?
EmptyTree,
- combineCasesNoSubstOnly(CODE.REF(exSym), scrutSym, casesNoSubstOnly, pt, matchOwner, scrut => Throw(CODE.REF(exSym)))
+ combineCasesNoSubstOnly(CODE.REF(exSym), scrutSym, casesNoSubstOnly, pt, matchOwner, Some(scrut => Throw(CODE.REF(exSym))))
)
})
}
@@ -262,9 +258,9 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
* @arg patBinder symbol used to refer to the result of the previous pattern's extractor (will later be replaced by the outer tree with the correct tree to refer to that patterns result)
*/
def unapply(tree: Tree): Option[(Symbol, Type)] = tree match {
- case Bound(subpatBinder, typed@Typed(expr, tpt)) => Some((subpatBinder, typed.tpe))
- case Bind(_, typed@Typed(expr, tpt)) => Some((patBinder, typed.tpe))
- case Typed(expr, tpt) => Some((patBinder, tree.tpe))
+ case Bound(subpatBinder, typed@Typed(expr, tpt)) if typed.tpe ne null => Some((subpatBinder, typed.tpe))
+ case Bind(_, typed@Typed(expr, tpt)) if typed.tpe ne null => Some((patBinder, typed.tpe))
+ case Typed(expr, tpt) if tree.tpe ne null => Some((patBinder, tree.tpe))
case _ => None
}
}
@@ -706,10 +702,10 @@ class Foo(x: Other) { x._1 } // no error in this order
def optimizeCases(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type): (List[List[TreeMaker]], List[Tree]) =
(cases, Nil)
- def emitSwitch(scrut: Tree, scrutSym: Symbol, cases: List[List[TreeMaker]], pt: Type): Option[Tree] =
+ def emitSwitch(scrut: Tree, scrutSym: Symbol, cases: List[List[TreeMaker]], pt: Type, matchFailGenOverride: Option[Tree => Tree]): Option[Tree] =
None
- // for catch
+ // for catch (no need to customize match failure)
def emitTypeSwitch(bindersAndCases: List[(Symbol, List[TreeMaker])], pt: Type): Option[List[CaseDef]] =
None
@@ -733,23 +729,25 @@ class Foo(x: Other) { x._1 } // no error in this order
private[this] var currSub: Substitution = null
// build Tree that chains `next` after the current extractor
- def chainBefore(next: Tree, pt: Type): Tree
+ def chainBefore(next: Tree)(casegen: Casegen): Tree
+ }
+
+ trait NoNewBinders extends TreeMaker {
+ protected val localSubstitution: Substitution = EmptySubstitution
}
- case class TrivialTreeMaker(tree: Tree) extends TreeMaker {
- val localSubstitution: Substitution = EmptySubstitution
- def chainBefore(next: Tree, pt: Type): Tree = tree
+ case class TrivialTreeMaker(tree: Tree) extends TreeMaker with NoNewBinders {
+ def chainBefore(next: Tree)(casegen: Casegen): Tree = tree
}
- case class BodyTreeMaker(body: Tree, matchPt: Type) extends TreeMaker {
- val localSubstitution: Substitution = EmptySubstitution
- def chainBefore(next: Tree, pt: Type): Tree = // assert(next eq EmptyTree)
- atPos(body.pos)(substitution(codegen.one(body, body.tpe, matchPt))) // since SubstOnly treemakers are dropped, need to do it here
+ case class BodyTreeMaker(body: Tree, matchPt: Type) extends TreeMaker with NoNewBinders {
+ def chainBefore(next: Tree)(casegen: Casegen): Tree = // assert(next eq EmptyTree)
+ atPos(body.pos)(casegen.one(substitution(body))) // since SubstOnly treemakers are dropped, need to do it here
}
case class SubstOnlyTreeMaker(prevBinder: Symbol, nextBinder: Symbol) extends TreeMaker {
val localSubstitution = Substitution(prevBinder, CODE.REF(nextBinder))
- def chainBefore(next: Tree, pt: Type): Tree = substitution(next)
+ def chainBefore(next: Tree)(casegen: Casegen): Tree = substitution(next)
}
abstract class FunTreeMaker extends TreeMaker {
@@ -766,8 +764,8 @@ class Foo(x: Other) { x._1 } // no error in this order
lazy val nextBinder = freshSym(pos, nextBinderTp)
lazy val localSubstitution = Substitution(List(prevBinder), List(CODE.REF(nextBinder)))
- def chainBefore(next: Tree, pt: Type): Tree =
- atPos(pos)(codegen.flatMapCond(cond, res, nextBinder, nextBinderTp, substitution(next)))
+ def chainBefore(next: Tree)(casegen: Casegen): Tree =
+ atPos(pos)(casegen.flatMapCond(cond, res, nextBinder, substitution(next)))
}
/**
@@ -778,11 +776,11 @@ class Foo(x: Other) { x._1 } // no error in this order
* in this function's body, and all the subsequent ones, references to the symbols in `from` will be replaced by the corresponding tree in `to`
*/
case class ExtractorTreeMaker(extractor: Tree, extraCond: Option[Tree], nextBinder: Symbol, localSubstitution: Substitution)(extractorReturnsBoolean: Boolean) extends FunTreeMaker {
- def chainBefore(next: Tree, pt: Type): Tree = {
- val condAndNext = extraCond map (codegen.ifThenElseZero(_, next)) getOrElse next
+ def chainBefore(next: Tree)(casegen: Casegen): Tree = {
+ val condAndNext = extraCond map (casegen.ifThenElseZero(_, next)) getOrElse next
atPos(extractor.pos)(
- if (extractorReturnsBoolean) codegen.flatMapCond(extractor, CODE.UNIT, nextBinder, nextBinder.info.widen, substitution(condAndNext))
- else codegen.flatMap(extractor, nextBinder, substitution(condAndNext))
+ if (extractorReturnsBoolean) casegen.flatMapCond(extractor, CODE.UNIT, nextBinder, substitution(condAndNext))
+ else casegen.flatMap(extractor, nextBinder, substitution(condAndNext))
)
}
@@ -791,10 +789,10 @@ class Foo(x: Other) { x._1 } // no error in this order
// TODO: allow user-defined unapplyProduct
case class ProductExtractorTreeMaker(prevBinder: Symbol, extraCond: Option[Tree], localSubstitution: Substitution) extends TreeMaker { import CODE._
- def chainBefore(next: Tree, pt: Type): Tree = {
+ def chainBefore(next: Tree)(casegen: Casegen): Tree = {
val nullCheck = REF(prevBinder) OBJ_NE NULL
val cond = extraCond map (nullCheck AND _) getOrElse nullCheck
- codegen.ifThenElseZero(cond, substitution(next))
+ casegen.ifThenElseZero(cond, substitution(next))
}
override def toString = "P"+(prevBinder, extraCond getOrElse "", localSubstitution)
@@ -907,61 +905,39 @@ class Foo(x: Other) { x._1 } // no error in this order
override def toString = "ET"+(prevBinder, patTree)
}
- case class AlternativesTreeMaker(prevBinder: Symbol, var altss: List[List[TreeMaker]], pos: Position) extends TreeMaker {
+ case class AlternativesTreeMaker(prevBinder: Symbol, var altss: List[List[TreeMaker]], pos: Position) extends TreeMaker with NoNewBinders {
// don't substitute prevBinder to nextBinder, a set of alternatives does not need to introduce a new binder, simply reuse the previous one
- val localSubstitution: Substitution = EmptySubstitution
override private[TreeMakers] def incorporateOuterSubstitution(outerSubst: Substitution): Unit = {
super.incorporateOuterSubstitution(outerSubst)
altss = altss map (alts => propagateSubstitution(alts, substitution))
}
- def chainBefore(next: Tree, pt: Type): Tree = { import CODE._
- // next does not contain deftrees, is pretty short
- val canDuplicate = {
- var okToInline = true
- var sizeBudget = 100 / (altss.length max 1) // yep, totally arbitrary!
- object travOkToInline extends Traverser { override def traverse(tree: Tree): Unit = if (sizeBudget >= 0) { sizeBudget -= 1; tree match {
- case TypeApply(_, _) | Apply(_, _) | Select(_, _)
- | Block(_, _) | Assign(_, _) | If(_, _, _) | Typed(_, _) => super.traverse(tree) // these are allowed if their subtrees are
- case EmptyTree | This(_) | New(_) | Literal(_) | Ident(_) => // these are always ok
- case _ if tree.isType => // these are always ok
- case _ => okToInline = false //; println("not inlining: "+ (tree, tree.getClass))
- }}}
- travOkToInline.traverse(next)
- // println("(okToInline, sizeBudget): "+ (okToInline, sizeBudget))
- okToInline && sizeBudget > 0 // must be strict comparison
- }
+ def chainBefore(next: Tree)(codegenAlt: Casegen): Tree = { import CODE._
+ atPos(pos){
+ // one alternative may still generate multiple trees (e.g., an extractor call + equality test)
+ // (for now,) alternatives may not bind variables (except wildcards), so we don't care about the final substitution built internally by makeTreeMakers
+ val combinedAlts = altss map (altTreeMakers =>
+ ((casegen: Casegen) => combineExtractors(altTreeMakers :+ TrivialTreeMaker(casegen.one(TRUE_typed)))(casegen))
+ )
- atPos(pos)(
- if (canDuplicate) {
- altss map {altTreeMakers =>
- combineExtractors(altTreeMakers :+ TrivialTreeMaker(substitution(next).duplicate), pt)
- } reduceLeft codegen.typedOrElse(pt)
- } else {
- val rest = freshSym(pos, functionType(List(), inMatchMonad(pt)), "rest")
- // rest.info.member(nme.apply).withAnnotation(AnnotationInfo(ScalaInlineClass.tpe, Nil, Nil))
-
- // one alternative may still generate multiple trees (e.g., an extractor call + equality test)
- // (for now,) alternatives may not bind variables (except wildcards), so we don't care about the final substitution built internally by makeTreeMakers
- val combinedAlts = altss map (altTreeMakers =>
- combineExtractors(altTreeMakers :+ TrivialTreeMaker(REF(rest) APPLY ()), pt)
- )
- BLOCK(
- VAL(rest) === Function(Nil, substitution(next)),
- combinedAlts reduceLeft codegen.typedOrElse(pt)
- )
- }
- )
+ val findAltMatcher = codegenAlt.matcher(EmptyTree, NoSymbol, BooleanClass.tpe)(combinedAlts, Some(x => FALSE_typed))
+ codegenAlt.ifThenElseZero(findAltMatcher, substitution(next))
+ }
}
}
- case class GuardTreeMaker(guardTree: Tree) extends TreeMaker {
- val localSubstitution: Substitution = EmptySubstitution
- def chainBefore(next: Tree, pt: Type): Tree = codegen.flatMapGuard(substitution(guardTree), next)
+ case class GuardTreeMaker(guardTree: Tree) extends TreeMaker with NoNewBinders {
+ def chainBefore(next: Tree)(casegen: Casegen): Tree = casegen.flatMapGuard(substitution(guardTree), next)
override def toString = "G("+ guardTree +")"
}
+ // combineExtractors changes the current substitution's of the tree makers in `treeMakers`
+ // requires propagateSubstitution(treeMakers) has been called
+ def combineExtractors(treeMakers: List[TreeMaker])(casegen: Casegen): Tree =
+ treeMakers.foldRight(EmptyTree: Tree)((a, b) => a.chainBefore(b)(casegen))
+
+
def removeSubstOnly(makers: List[TreeMaker]) = makers filterNot (_.isInstanceOf[SubstOnlyTreeMaker])
// a foldLeft to accumulate the localSubstitution left-to-right
@@ -976,51 +952,42 @@ class Foo(x: Other) { x._1 } // no error in this order
}
// calls propagateSubstitution on the treemakers
- def combineCases(scrut: Tree, scrutSym: Symbol, casesRaw: List[List[TreeMaker]], pt: Type, owner: Symbol): Tree = {
- val casesNoSubstOnly = casesRaw map (propagateSubstitution(_, EmptySubstitution)) // drops SubstOnlyTreeMakers, since their effect is now contained in the TreeMakers that follow them
- combineCasesNoSubstOnly(scrut, scrutSym, casesNoSubstOnly, pt, owner, CODE.MATCHERROR(_))
+ def combineCases(scrut: Tree, scrutSym: Symbol, casesRaw: List[List[TreeMaker]], pt: Type, owner: Symbol, matchFailGenOverride: Option[Tree => Tree]): Tree = {
+ // drops SubstOnlyTreeMakers, since their effect is now contained in the TreeMakers that follow them
+ val casesNoSubstOnly = casesRaw map (propagateSubstitution(_, EmptySubstitution))
+ combineCasesNoSubstOnly(scrut, scrutSym, casesNoSubstOnly, pt, owner, matchFailGenOverride)
}
- def combineCasesNoSubstOnly(scrut: Tree, scrutSym: Symbol, casesNoSubstOnly: List[List[TreeMaker]], pt: Type, owner: Symbol, matchFail: Tree => Tree): Tree = fixerUpper(owner, scrut.pos){
- emitSwitch(scrut, scrutSym, casesNoSubstOnly, pt).getOrElse{
- val (matcher, hasDefault, toHoist) =
- if (casesNoSubstOnly nonEmpty) {
- // when specified, need to propagate pt explicitly (type inferencer can't handle it)
- val optPt =
- if (isFullyDefined(pt)) inMatchMonad(pt)
- else NoType
+ def combineCasesNoSubstOnly(scrut: Tree, scrutSym: Symbol, casesNoSubstOnly: List[List[TreeMaker]], pt: Type, owner: Symbol, matchFailGenOverride: Option[Tree => Tree]): Tree =
+ fixerUpper(owner, scrut.pos){
+ val ptDefined = if (isFullyDefined(pt)) pt else NoType
+ def matchFailGen = (matchFailGenOverride orElse Some(CODE.MATCHERROR(_: Tree)))
- // do this check on casesNoSubstOnly, since DCE will eliminate trivial cases like `case _ =>`, even if they're the last one
+ emitSwitch(scrut, scrutSym, casesNoSubstOnly, pt, matchFailGenOverride).getOrElse{
+ if (casesNoSubstOnly nonEmpty) {
+ // before optimizing, check casesNoSubstOnly for presence of a default case,
+ // since DCE will eliminate trivial cases like `case _ =>`, even if they're the last one
// exhaustivity and reachability must be checked before optimization as well
- // TODO: improve, a trivial type test before the body still makes for a default case
- // ("trivial" depends on whether we're emitting a straight match or an exception, or more generally, any supertype of scrutSym.tpe is a no-op)
- val hasDefault = casesNoSubstOnly.nonEmpty && {
- val nonTrivLast = casesNoSubstOnly.last
- nonTrivLast.nonEmpty && nonTrivLast.head.isInstanceOf[BodyTreeMaker]
- }
+ // TODO: improve notion of trivial/irrefutable -- a trivial type test before the body still makes for a default case
+ // ("trivial" depends on whether we're emitting a straight match or an exception, or more generally, any supertype of scrutSym.tpe is a no-op)
+ // irrefutability checking should use the approximation framework also used for CSE, unreachability and exhaustivity checking
+ val synthCatchAll =
+ if (casesNoSubstOnly.nonEmpty && {
+ val nonTrivLast = casesNoSubstOnly.last
+ nonTrivLast.nonEmpty && nonTrivLast.head.isInstanceOf[BodyTreeMaker]
+ }) None
+ else matchFailGen
val (cases, toHoist) = optimizeCases(scrutSym, casesNoSubstOnly, pt)
- val combinedCases =
- cases.map(combineExtractors(_, pt)).reduceLeft(codegen.typedOrElse(optPt))
-
- (combinedCases, hasDefault, toHoist)
- } else (codegen.zero, false, Nil)
+ val matchRes = codegen.matcher(scrut, scrutSym, pt)(cases map combineExtractors, synthCatchAll)
- // catch-all
- val catchAll =
- if (hasDefault) None // no need for a catch-all when there's already a default
- else Some(matchFail)
- val expr = codegen.runOrElse(scrut, scrutSym, matcher, if (isFullyDefined(pt)) pt else NoType, catchAll)
- if (toHoist isEmpty) expr
- else Block(toHoist, expr)
+ if (toHoist isEmpty) matchRes else Block(toHoist, matchRes)
+ } else {
+ codegen.matcher(scrut, scrutSym, pt)(Nil, matchFailGen)
+ }
+ }
}
- }
-
- // combineExtractors changes the current substitution's of the tree makers in `treeMakers`
- // requires propagateSubstitution(treeMakers) has been called
- def combineExtractors(treeMakers: List[TreeMaker], pt: Type): Tree =
- treeMakers.foldRight (EmptyTree: Tree) (_.chainBefore(_, pt))
// TODO: do this during tree construction, but that will require tracking the current owner in treemakers
// TODO: assign more fine-grained positions
@@ -1070,34 +1037,36 @@ class Foo(x: Other) { x._1 } // no error in this order
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
trait CodegenCore extends MatchMonadInterface {
private var ctr = 0
- def freshSym(pos: Position, tp: Type = NoType, prefix: String = "x") = {ctr += 1;
- // assert(owner ne null)
- // assert(owner ne NoSymbol)
- NoSymbol.newTermSymbol(vpmName.counted(prefix, ctr), pos) setInfo repackExistential(tp)
- }
+ def freshName(prefix: String) = {ctr += 1; vpmName.counted(prefix, ctr)}
+
+ // assert(owner ne null); assert(owner ne NoSymbol)
+ def freshSym(pos: Position, tp: Type = NoType, prefix: String = "x") =
+ NoSymbol.newTermSymbol(freshName(prefix), pos) setInfo /*repackExistential*/(tp)
// codegen relevant to the structure of the translation (how extractors are combined)
trait AbsCodegen {
- def runOrElse(scrut: Tree, scrutSym: Symbol, matcher: Tree, resTp: Type, catchAll: Option[Tree => Tree]): Tree
- def one(res: Tree, bodyPt: Type, matchPt: Type): Tree
- def zero: Tree
- def flatMap(prev: Tree, b: Symbol, next: Tree): Tree
- def typedOrElse(pt: Type)(thisCase: Tree, elseCase: Tree): Tree
+ def matcher(scrut: Tree, scrutSym: Symbol, restpe: Type)(cases: List[Casegen => Tree], matchFailGen: Option[Tree => Tree]): Tree
- def flatMapCond(cond: Tree, res: Tree, nextBinder: Symbol, nextBinderTp: Type, next: Tree): Tree
- def flatMapGuard(cond: Tree, next: Tree): Tree
-
- def fun(arg: Symbol, body: Tree): Tree
- def ifThenElseZero(c: Tree, then: Tree): Tree
- def _equals(checker: Tree, binder: Symbol): Tree
+ // local / context-free
def _asInstanceOf(b: Symbol, tp: Type): Tree
+ def _equals(checker: Tree, binder: Symbol): Tree
+ def _isInstanceOf(b: Symbol, tp: Type): Tree
+ def and(a: Tree, b: Tree): Tree
+ def drop(tgt: Tree)(n: Int): Tree
+ def index(tgt: Tree)(i: Int): Tree
def mkZero(tp: Type): Tree
-
def tupleSel(binder: Symbol)(i: Int): Tree
- def index(tgt: Tree)(i: Int): Tree
- def drop(tgt: Tree)(n: Int): Tree
- def and(a: Tree, b: Tree): Tree
- def _isInstanceOf(b: Symbol, tp: Type): Tree
+ }
+
+ // structure
+ trait Casegen extends AbsCodegen { import CODE._
+ def one(res: Tree): Tree
+
+ def flatMap(prev: Tree, b: Symbol, next: Tree): Tree
+ def flatMapCond(cond: Tree, res: Tree, nextBinder: Symbol, next: Tree): Tree
+ def flatMapGuard(cond: Tree, next: Tree): Tree
+ def ifThenElseZero(c: Tree, then: Tree): Tree = IF (c) THEN then ELSE zero
+ protected def zero: Tree
}
def codegen: AbsCodegen
@@ -1112,21 +1081,20 @@ class Foo(x: Other) { x._1 } // no error in this order
def drop(tgt: Tree)(n: Int): Tree = (tgt DOT vpmName.drop) (LIT(n))
def _equals(checker: Tree, binder: Symbol): Tree = checker MEMBER_== REF(binder) // NOTE: checker must be the target of the ==, that's the patmat semantics for ya
def and(a: Tree, b: Tree): Tree = a AND b
- def ifThenElseZero(c: Tree, then: Tree): Tree = IF (c) THEN then ELSE zero
// the force is needed mainly to deal with the GADT typing hack (we can't detect it otherwise as tp nor pt need contain an abstract type, we're just casting wildly)
- def _asInstanceOf(t: Tree, tp: Type, force: Boolean = false): Tree = { val tpX = repackExistential(tp)
+ def _asInstanceOf(t: Tree, tp: Type, force: Boolean = false): Tree = { val tpX = /*repackExistential*/(tp)
if (!force && (t.tpe ne NoType) && t.isTyped && typesConform(t.tpe, tpX)) t //{ println("warning: emitted redundant asInstanceOf: "+(t, t.tpe, tp)); t } //.setType(tpX)
else gen.mkAsInstanceOf(t, tpX, true, false)
}
- def _isInstanceOf(b: Symbol, tp: Type): Tree = gen.mkIsInstanceOf(REF(b), repackExistential(tp), true, false)
- // { val tpX = repackExistential(tp)
+ def _isInstanceOf(b: Symbol, tp: Type): Tree = gen.mkIsInstanceOf(REF(b), /*repackExistential*/(tp), true, false)
+ // { val tpX = /*repackExistential*/(tp)
// if (typesConform(b.info, tpX)) { println("warning: emitted spurious isInstanceOf: "+(b, tp)); TRUE }
// else gen.mkIsInstanceOf(REF(b), tpX, true, false)
// }
- def _asInstanceOf(b: Symbol, tp: Type): Tree = { val tpX = repackExistential(tp)
+ def _asInstanceOf(b: Symbol, tp: Type): Tree = { val tpX = /*repackExistential*/(tp)
if (typesConform(b.info, tpX)) REF(b) //{ println("warning: emitted redundant asInstanceOf: "+(b, b.info, tp)); REF(b) } //.setType(tpX)
else gen.mkAsInstanceOf(REF(b), tpX, true, false)
}
@@ -1166,28 +1134,29 @@ class Foo(x: Other) { x._1 } // no error in this order
trait PureCodegen extends CodegenCore with PureMatchMonadInterface {
def codegen: AbsCodegen = pureCodegen
- object pureCodegen extends CommonCodegen { import CODE._
+ object pureCodegen extends CommonCodegen with Casegen { import CODE._
//// methods in MatchingStrategy (the monad companion) -- used directly in translation
// __match.runOrElse(`scrut`)(`scrutSym` => `matcher`)
// TODO: consider catchAll, or virtualized matching will break in exception handlers
- def runOrElse(scrut: Tree, scrutSym: Symbol, matcher: Tree, resTp: Type, catchAll: Option[Tree => Tree]): Tree
- = _match(vpmName.runOrElse) APPLY (scrut) APPLY (fun(scrutSym, matcher))
+ def matcher(scrut: Tree, scrutSym: Symbol, restpe: Type)(cases: List[Casegen => Tree], matchFailGen: Option[Tree => Tree]): Tree =
+ _match(vpmName.runOrElse) APPLY (scrut) APPLY (fun(scrutSym, cases map (f => f(this)) reduceLeft typedOrElse))
+
// __match.one(`res`)
- def one(res: Tree, bodyPt: Type, matchPt: Type): Tree = (_match(vpmName.one)) (res)
+ def one(res: Tree): Tree = (_match(vpmName.one)) (res)
// __match.zero
- def zero: Tree = _match(vpmName.zero)
+ protected def zero: Tree = _match(vpmName.zero)
// __match.guard(`c`, `then`)
- def guard(c: Tree, then: Tree, tp: Type): Tree = _match(vpmName.guard) APPLY (c, then)
+ def guard(c: Tree, then: Tree): Tree = _match(vpmName.guard) APPLY (c, then)
//// methods in the monad instance -- used directly in translation
// `prev`.flatMap(`b` => `next`)
def flatMap(prev: Tree, b: Symbol, next: Tree): Tree = (prev DOT vpmName.flatMap)(fun(b, next))
// `thisCase`.orElse(`elseCase`)
- def typedOrElse(pt: Type)(thisCase: Tree, elseCase: Tree): Tree = (thisCase DOT vpmName.orElse) APPLY (elseCase)
+ def typedOrElse(thisCase: Tree, elseCase: Tree): Tree = (thisCase DOT vpmName.orElse) APPLY (elseCase)
// __match.guard(`cond`, `res`).flatMap(`nextBinder` => `next`)
- def flatMapCond(cond: Tree, res: Tree, nextBinder: Symbol, nextBinderTp: Type, next: Tree): Tree = flatMap(guard(cond, res, nextBinderTp), nextBinder, next)
+ def flatMapCond(cond: Tree, res: Tree, nextBinder: Symbol, next: Tree): Tree = flatMap(guard(cond, res), nextBinder, next)
// __match.guard(`guardTree`, ()).flatMap((_: P[Unit]) => `next`)
- def flatMapGuard(guardTree: Tree, next: Tree): Tree = flatMapCond(guardTree, CODE.UNIT, freshSym(guardTree.pos, pureType(UnitClass.tpe)), pureType(UnitClass.tpe), next)
+ def flatMapGuard(guardTree: Tree, next: Tree): Tree = flatMapCond(guardTree, CODE.UNIT, freshSym(guardTree.pos, pureType(UnitClass.tpe)), next)
}
}
@@ -1456,8 +1425,8 @@ class Foo(x: Other) { x._1 } // no error in this order
}
// TODO: finer-grained duplication
- def chainBefore(next: Tree, pt: Type): Tree = // assert(codegen eq optimizedCodegen)
- atPos(pos)(optimizedCodegen.flatMapCondStored(cond, storedCond, res, nextBinder, substitution(next).duplicate))
+ def chainBefore(next: Tree)(casegen: Casegen): Tree = // assert(codegen eq optimizedCodegen)
+ atPos(pos)(casegen.asInstanceOf[optimizedCodegen.OptimizedCasegen].flatMapCondStored(cond, storedCond, res, nextBinder, substitution(next).duplicate))
}
case class ReusingCondTreeMaker(sharedPrefix: List[Test], toReused: TreeMaker => TreeMaker) extends TreeMaker { import CODE._
@@ -1474,12 +1443,11 @@ class Foo(x: Other) { x._1 } // no error in this order
oldSubs.foldLeft(Substitution(from, to))(_ >> _)
}
- def chainBefore(next: Tree, pt: Type): Tree = {
+ def chainBefore(next: Tree)(casegen: Casegen): Tree = {
val cond = REF(dropped_priors.reverse.collectFirst{case (_, Some(ctm: ReusedCondTreeMaker)) => ctm}.get.storedCond)
- IF (cond) THEN BLOCK(
- substitution(next).duplicate // TODO: finer-grained duplication -- MUST duplicate though, or we'll get VerifyErrors since sharing trees confuses lambdalift, and its confusion it emits illegal casts (diagnosed by Grzegorz: checkcast T ; invokevirtual S.m, where T not a subtype of S)
- ) ELSE codegen.zero
+ // TODO: finer-grained duplication -- MUST duplicate though, or we'll get VerifyErrors since sharing trees confuses lambdalift, and its confusion it emits illegal casts (diagnosed by Grzegorz: checkcast T ; invokevirtual S.m, where T not a subtype of S)
+ casegen.ifThenElseZero(cond, substitution(next).duplicate)
}
}
}
@@ -1551,7 +1519,7 @@ class Foo(x: Other) { x._1 } // no error in this order
}
}
- class RegularSwitchMaker(scrutSym: Symbol) extends SwitchMaker {
+ class RegularSwitchMaker(scrutSym: Symbol, matchFailGenOverride: Option[Tree => Tree]) extends SwitchMaker {
val switchableTpe = Set(ByteClass.tpe, ShortClass.tpe, IntClass.tpe, CharClass.tpe)
val alternativesSupported = true
@@ -1574,14 +1542,14 @@ class Foo(x: Other) { x._1 } // no error in this order
}
def defaultSym: Symbol = scrutSym
- def defaultBody: Tree = { import CODE._; MATCHERROR(REF(scrutSym)) }
+ def defaultBody: Tree = { import CODE._; matchFailGenOverride map (gen => gen(REF(scrutSym))) getOrElse MATCHERROR(REF(scrutSym)) }
def defaultCase(scrutSym: Symbol = defaultSym, body: Tree = defaultBody): CaseDef = { import CODE._; atPos(body.pos) {
DEFAULT ==> body
}}
}
- override def emitSwitch(scrut: Tree, scrutSym: Symbol, cases: List[List[TreeMaker]], pt: Type): Option[Tree] = { import CODE._
- val regularSwitchMaker = new RegularSwitchMaker(scrutSym)
+ override def emitSwitch(scrut: Tree, scrutSym: Symbol, cases: List[List[TreeMaker]], pt: Type, matchFailGenOverride: Option[Tree => Tree]): Option[Tree] = { import CODE._
+ val regularSwitchMaker = new RegularSwitchMaker(scrutSym, matchFailGenOverride)
// TODO: if patterns allow switch but the type of the scrutinee doesn't, cast (type-test) the scrutinee to the corresponding switchable type and switch on the result
if (regularSwitchMaker.switchableTpe(scrutSym.tpe)) {
val caseDefsWithDefault = regularSwitchMaker(cases map {c => (scrutSym, c)}, pt)
@@ -1589,11 +1557,11 @@ class Foo(x: Other) { x._1 } // no error in this order
else {
// match on scrutSym -- converted to an int if necessary -- not on scrut directly (to avoid duplicating scrut)
val scrutToInt: Tree =
- if(scrutSym.tpe =:= IntClass.tpe) REF(scrutSym)
+ if (scrutSym.tpe =:= IntClass.tpe) REF(scrutSym)
else (REF(scrutSym) DOT (nme.toInt))
Some(BLOCK(
VAL(scrutSym) === scrut,
- Match(scrutToInt, caseDefsWithDefault)
+ Match(gen.mkSynthSwitchSelector(scrutToInt), caseDefsWithDefault) // add switch annotation
))
}
} else None
@@ -1657,8 +1625,7 @@ class Foo(x: Other) { x._1 } // no error in this order
// for example, `o.flatMap(f)` becomes `if(o == None) None else f(o.get)`, similarly for orElse and guard
// this is a special instance of the advanced inlining optimization that takes a method call on
// an object of a type that only has two concrete subclasses, and inlines both bodies, guarded by an if to distinguish the two cases
- object optimizedCodegen extends CommonCodegen /*with AbsOptimizedCodegen*/ { import CODE._
- lazy val zeroSym = freshSym(NoPosition, optionType(NothingClass.tpe), "zero")
+ object optimizedCodegen extends CommonCodegen { import CODE._
/** Inline runOrElse and get rid of Option allocations
*
@@ -1666,67 +1633,92 @@ class Foo(x: Other) { x._1 } // no error in this order
* the matcher's optional result is encoded as a flag, keepGoing, where keepGoing == true encodes result.isEmpty,
* if keepGoing is false, the result Some(x) of the naive translation is encoded as matchRes == x
*/
- @inline private def dontStore(tp: Type) = (tp.typeSymbol eq UnitClass) || (tp.typeSymbol eq NothingClass)
- lazy val keepGoing = freshSym(NoPosition, BooleanClass.tpe, "keepGoing") setFlag MUTABLE
- lazy val matchRes = freshSym(NoPosition, AnyClass.tpe, "matchRes") setFlag MUTABLE
- def runOrElse(scrut: Tree, scrutSym: Symbol, matcher: Tree, resTp: Type, catchAll: Option[Tree => Tree]) = {
- matchRes.info = if (resTp ne NoType) resTp.widen else AnyClass.tpe // we don't always know resTp, and it might be AnyVal, in which case we can't assign NULL
- if (dontStore(resTp)) matchRes resetFlag MUTABLE // don't assign to Unit-typed var's, in fact, make it a val -- conveniently also works around SI-5245
- BLOCK(
- VAL(zeroSym) === REF(NoneModule), // TODO: can we just get rid of explicitly emitted zero? don't know how to do that as a local rewrite...
- VAL(scrutSym) === scrut,
- VAL(matchRes) === mkZero(matchRes.info), // must cast to deal with GADT typing, hence the private mkZero above
- VAL(keepGoing) === TRUE,
- matcher,
- catchAll map { catchAllGen => (IF (REF(keepGoing)) THEN catchAllGen(REF(scrutSym)) ELSE REF(matchRes)) } getOrElse REF(matchRes)
- )
- }
+ def matcher(scrut: Tree, scrutSym: Symbol, restpe: Type)(cases: List[Casegen => Tree], matchFailGen: Option[Tree => Tree]): Tree = {
+ val matchEnd = NoSymbol.newLabel(freshName("matchEnd"), NoPosition) setFlag SYNTH_CASE
+ val matchRes = NoSymbol.newValueParameter(newTermName("x"), NoPosition, SYNTHETIC) setInfo restpe
+ matchEnd setInfo MethodType(List(matchRes), restpe)
+
+ def newCaseSym = NoSymbol.newLabel(freshName("case"), NoPosition) setInfo MethodType(Nil, restpe) setFlag SYNTH_CASE
+ var nextCase = newCaseSym
+ def caseDef(mkCase: Casegen => Tree): Tree = {
+ val currCase = nextCase
+ nextCase = newCaseSym
+ val casegen = new OptimizedCasegen(matchEnd, nextCase, restpe)
+ LabelDef(currCase, Nil, mkCase(casegen))
+ }
- // only used to wrap the RHS of a body
- def one(res: Tree, bodyPt: Type, matchPt: Type): Tree = {
- BLOCK(
- REF(keepGoing) === FALSE, // comes before assignment to matchRes, so the latter is in tail positions (can ignore the trailing zero -- will disappear when we flatten blocks, which is TODO)
- if (dontStore(matchPt)) res else (REF(matchRes) === res), // runOrElse hasn't been called yet, so matchRes.isMutable is irrelevant, also, tp may be a subtype of resTp used in runOrElse...
- zero // to have a nice lub for lubs -- otherwise we'll get a boxed unit here -- TODO: get rid of all those dangling else zero's
+ def catchAll = matchFailGen map { matchFailGen =>
+ val scrutRef = if(scrutSym ne NoSymbol) REF(scrutSym) else EmptyTree // for alternatives
+ LabelDef(nextCase, Nil, matchEnd APPLY (_asInstanceOf(matchFailGen(scrutRef), restpe))) // need to jump to matchEnd with result generated by matchFailGen (could be `FALSE` for isDefinedAt)
+ } toList
+ // catchAll.isEmpty iff no synthetic default case needed (the (last) user-defined case is a default)
+ // if the last user-defined case is a default, it will never jump to the next case; it will go immediately to matchEnd
+
+ // the generated block is taken apart in TailCalls under the following assumptions
+ // the assumption is once we encounter a case, the remainder of the block will consist of cases
+ // the prologue may be empty, usually it is the valdef that stores the scrut
+ // val (prologue, cases) = stats span (s => !s.isInstanceOf[LabelDef])
+
+ // scrutSym == NoSymbol when generating an alternatives matcher
+ val scrutDef = if(scrutSym ne NoSymbol) List(VAL(scrutSym) === scrut) else Nil // for alternatives
+ Block(
+ scrutDef ++ (cases map caseDef) ++ catchAll,
+ LabelDef(matchEnd, List(matchRes), REF(matchRes))
)
}
- def zero: Tree = REF(zeroSym)
-
- def flatMap(prev: Tree, b: Symbol, next: Tree): Tree = {
- val tp = inMatchMonad(b.tpe)
- val prevSym = freshSym(prev.pos, tp, "o")
- val isEmpty = tp member vpmName.isEmpty
- val get = tp member vpmName.get
+ class OptimizedCasegen(matchEnd: Symbol, nextCase: Symbol, restpe: Type) extends CommonCodegen with Casegen {
+ def matcher(scrut: Tree, scrutSym: Symbol, restpe: Type)(cases: List[Casegen => Tree], matchFailGen: Option[Tree => Tree]): Tree =
+ optimizedCodegen.matcher(scrut, scrutSym, restpe)(cases, matchFailGen)
+
+ // only used to wrap the RHS of a body
+ // res: T
+ // returns MatchMonad[T]
+ def one(res: Tree): Tree = matchEnd APPLY (_asInstanceOf(res, restpe)) // need cast for GADT magic
+ protected def zero: Tree = nextCase APPLY ()
+
+ // prev: MatchMonad[T]
+ // b: T
+ // next: MatchMonad[U]
+ // returns MatchMonad[U]
+ def flatMap(prev: Tree, b: Symbol, next: Tree): Tree = {
+ val tp = inMatchMonad(b.tpe)
+ val prevSym = freshSym(prev.pos, tp, "o")
+ val isEmpty = tp member vpmName.isEmpty
+ val get = tp member vpmName.get
+
+ BLOCK(
+ VAL(prevSym) === prev,
+ // must be isEmpty and get as we don't control the target of the call (prev is an extractor call)
+ ifThenElseZero(NOT(prevSym DOT isEmpty), Substitution(b, prevSym DOT get)(next))
+ )
+ }
- BLOCK(
- VAL(prevSym) === prev,
- IF (prevSym DOT isEmpty) THEN zero ELSE Substitution(b, prevSym DOT get)(next) // must be isEmpty and get as we don't control the target of the call (could be the result of a user-defined extractor)
- )
- }
+ // cond: Boolean
+ // res: T
+ // nextBinder: T
+ // next == MatchMonad[U]
+ // returns MatchMonad[U]
+ def flatMapCond(cond: Tree, res: Tree, nextBinder: Symbol, next: Tree): Tree =
+ ifThenElseZero(cond, BLOCK(
+ VAL(nextBinder) === res,
+ next
+ ))
- def typedOrElse(pt: Type)(thisCase: Tree, elseCase: Tree): Tree = {
- BLOCK(
- thisCase,
- IF (REF(keepGoing)) THEN elseCase ELSE zero // leave trailing zero for now, otherwise typer adds () anyway
- )
+ // guardTree: Boolean
+ // next: MatchMonad[T]
+ // returns MatchMonad[T]
+ def flatMapGuard(guardTree: Tree, next: Tree): Tree =
+ ifThenElseZero(guardTree, next)
+
+ def flatMapCondStored(cond: Tree, condSym: Symbol, res: Tree, nextBinder: Symbol, next: Tree): Tree =
+ ifThenElseZero(cond, BLOCK(
+ condSym === TRUE_typed,
+ nextBinder === res,
+ next
+ ))
}
- def flatMapCond(cond: Tree, res: Tree, nextBinder: Symbol, nextBinderTp: Type, next: Tree): Tree =
- IF (cond) THEN BLOCK(
- VAL(nextBinder) === res,
- next
- ) ELSE zero
-
- def flatMapCondStored(cond: Tree, condSym: Symbol, res: Tree, nextBinder: Symbol, next: Tree): Tree =
- IF (cond) THEN BLOCK(
- condSym === TRUE,
- nextBinder === res,
- next
- ) ELSE zero
-
- def flatMapGuard(guardTree: Tree, next: Tree): Tree =
- IF (guardTree) THEN next ELSE zero
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index ec42d251ff..045614e773 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -266,7 +266,8 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
(if (showLocation)
sym1.locationString +
(if (sym1.isAliasType) ", which equals "+self.memberInfo(sym1)
- else if (sym1.isAbstractType) " with bounds "+self.memberInfo(sym1)
+ else if (sym1.isAbstractType) " with bounds"+self.memberInfo(sym1)
+ else if (sym1.isModule) ""
else if (sym1.isTerm) " of type "+self.memberInfo(sym1)
else "")
else "")
@@ -394,9 +395,14 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
overrideError("needs `override' modifier")
} else if (other.isAbstractOverride && other.isIncompleteIn(clazz) && !member.isAbstractOverride) {
overrideError("needs `abstract override' modifiers")
- } else if (member.isAnyOverride && (other hasFlag ACCESSOR) && other.accessed.isVariable && !other.accessed.isLazy) {
- overrideError("cannot override a mutable variable")
- } else if (member.isAnyOverride &&
+ }
+ else if (member.isAnyOverride && (other hasFlag ACCESSOR) && other.accessed.isVariable && !other.accessed.isLazy) {
+ // !?! this is not covered by the spec. We need to resolve this either by changing the spec or removing the test here.
+ // !!! is there a !?! convention? I'm !!!ing this to make sure it turns up on my searches.
+ if (!settings.overrideVars.value)
+ overrideError("cannot override a mutable variable")
+ }
+ else if (member.isAnyOverride &&
!(member.owner.thisType.baseClasses exists (_ isSubClass other.owner)) &&
!member.isDeferred && !other.isDeferred &&
intersectionIsEmpty(member.extendedOverriddenSymbols, other.extendedOverriddenSymbols)) {
@@ -1248,9 +1254,9 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
}
List(tree1)
}
- case Import(_, _) => Nil
+ case Import(_, _) => Nil
case DefDef(mods, _, _, _, _, _) if (mods hasFlag MACRO) => Nil
- case _ => List(transform(tree))
+ case _ => List(transform(tree))
}
/* Check whether argument types conform to bounds of type parameters */
@@ -1445,7 +1451,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
private def transformApply(tree: Apply): Tree = tree match {
case Apply(
- Select(qual, nme.filter),
+ Select(qual, nme.filter | nme.withFilter),
List(Function(
List(ValDef(_, pname, tpt, _)),
Match(_, CaseDef(pat1, _, _) :: _))))
@@ -1625,12 +1631,18 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
case _ => tree
}
+ // skip refchecks in patterns....
result = result match {
case CaseDef(pat, guard, body) =>
inPattern = true
val pat1 = transform(pat)
inPattern = false
treeCopy.CaseDef(tree, pat1, transform(guard), transform(body))
+ case LabelDef(_, _, _) if gen.hasSynthCaseSymbol(result) =>
+ inPattern = true
+ val res = deriveLabelDef(result)(transform)
+ inPattern = false
+ res
case _ =>
super.transform(result)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index 4248b6f024..94733369a8 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -259,7 +259,8 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
case sel @ Select(Super(_, mix), name) =>
if (sym.isValue && !sym.isMethod || sym.hasAccessorFlag) {
- unit.error(tree.pos, "super may be not be used on "+ sym.accessedOrSelf)
+ if (!settings.overrideVars.value)
+ unit.error(tree.pos, "super may be not be used on "+ sym.accessedOrSelf)
}
else if (isDisallowed(sym)) {
unit.error(tree.pos, "super not allowed here: use this." + name.decode + " instead")
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index 2f4eff30d2..da87d38ab0 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -136,7 +136,7 @@ trait SyntheticMethods extends ast.TreeDSL {
* where that is the given methods first parameter.
*/
def thatTest(eqmeth: Symbol): Tree =
- gen.mkIsInstanceOf(Ident(eqmeth.firstParam), typeCaseType(clazz), true, false)
+ gen.mkIsInstanceOf(Ident(eqmeth.firstParam), classExistentialType(clazz), true, false)
/** (that.asInstanceOf[this.C])
* where that is the given methods first parameter.
diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
index ed263cbbef..105c2c0b98 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
@@ -263,8 +263,8 @@ abstract class TreeCheckers extends Analyzer {
tree match {
case x: PackageDef =>
- if (sym.ownerChain contains currentOwner) ()
- else fail(sym + " owner chain does not contain currentOwner " + currentOwner)
+ if ((sym.ownerChain contains currentOwner) || currentOwner == definitions.EmptyPackageClass) ()
+ else fail(sym + " owner chain does not contain currentOwner " + currentOwner + sym.ownerChain)
case _ =>
def cond(s: Symbol) = !s.isTerm || s.isMethod || s == sym.owner
diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
index 1434002121..6efa595d99 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
@@ -157,7 +157,7 @@ trait TypeDiagnostics {
}
// todo: use also for other error messages
- def existentialContext(tp: Type) = tp.existentialSkolems match {
+ def existentialContext(tp: Type) = tp.skolemsExceptMethodTypeParams match {
case Nil => ""
case xs => " where " + (disambiguate(xs map (_.existentialToString)) mkString ", ")
}
@@ -252,12 +252,17 @@ trait TypeDiagnostics {
}
"" // no elaborable variance situation found
}
- def foundReqMsg(found: Type, req: Type): String = (
- withDisambiguation(Nil, found, req)(
+ // TODO - figure out how to avoid doing any work at all
+ // when the message will never be seen. I though context.reportErrors
+ // being false would do that, but if I return "<suppressed>" under
+ // that condition, I see it.
+ def foundReqMsg(found: Type, req: Type): String = {
+ def baseMessage = (
";\n found : " + found.toLongString + existentialContext(found) + explainAlias(found) +
"\n required: " + req + existentialContext(req) + explainAlias(req)
- ) + explainVariance(found, req)
- )
+ )
+ withDisambiguation(Nil, found, req)(baseMessage) + explainVariance(found, req)
+ }
case class TypeDiag(tp: Type, sym: Symbol) extends Ordered[TypeDiag] {
// save the name because it will be mutated until it has been
@@ -307,16 +312,37 @@ trait TypeDiagnostics {
)
}
}
- private def typeDiags(locals: List[Symbol], types: Type*): List[TypeDiag] = {
- object SymExtractor {
- def unapply(x: Any) = x match {
- case t @ ConstantType(_) => Some(t -> t.underlying.typeSymbol)
- case t @ TypeRef(_, sym, _) => if (locals contains sym) None else Some(t -> sym)
- case _ => None
+ /** This is tricky stuff - we need to traverse types deeply to
+ * explain name ambiguities, which may occur anywhere. However
+ * when lub explosions come through it knocks us into an n^2
+ * disaster, see SI-5580. This is trying to perform the initial
+ * filtering of possibly ambiguous types in a sufficiently
+ * aggressive way that the state space won't explode.
+ */
+ private def typeDiags(locals: List[Symbol], types0: Type*): List[TypeDiag] = {
+ val types = types0.toList
+ // If two different type diag instances are seen for a given
+ // key (either the string representation of a type, or the simple
+ // name of a symbol) then keep them for disambiguation.
+ val strings = mutable.Map[String, Set[TypeDiag]]() withDefaultValue Set()
+ val names = mutable.Map[Name, Set[TypeDiag]]() withDefaultValue Set()
+
+ def record(t: Type, sym: Symbol) = {
+ val diag = TypeDiag(t, sym)
+
+ strings("" + t) += diag
+ names(sym.name) += diag
+ }
+ for (tpe <- types ; t <- tpe) {
+ t match {
+ case ConstantType(_) => record(t, t.underlying.typeSymbol)
+ case TypeRef(_, sym, _) => record(t, sym)
+ case _ => ()
}
}
- for (tp <- types.toList; SymExtractor(t, sym) <- tp) yield TypeDiag(t, sym)
+ val collisions = strings.values ++ names.values filter (_.size > 1)
+ collisions.flatten.toList
}
/** The distinct pairs from an ordered list. */
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 25f3e7af5c..2aff00f6a5 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -235,32 +235,41 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
result
}
}
+ def isNonRefinementClassType(tpe: Type) = tpe match {
+ case SingleType(_, sym) => sym.isModuleClass
+ case TypeRef(_, sym, _) => sym.isClass && !sym.isRefinementClass
+ case ErrorType => true
+ case _ => false
+ }
+ private def errorNotClass(tpt: Tree, found: Type) = { ClassTypeRequiredError(tpt, found); false }
+ private def errorNotStable(tpt: Tree, found: Type) = { TypeNotAStablePrefixError(tpt, found); false }
/** Check that `tpt` refers to a non-refinement class type */
- def checkClassType(tpt: Tree, existentialOK: Boolean, stablePrefix: Boolean): Boolean = {
- def errorNotClass(found: AnyRef) = { ClassTypeRequiredError(tpt, found); false }
- def check(tpe: Type): Boolean = tpe.normalize match {
- case TypeRef(pre, sym, _) if sym.isClass && !sym.isRefinementClass =>
- if (stablePrefix && !isPastTyper)
- if (!pre.isStable) {
- TypeNotAStablePrefixError(tpt, pre)
- false
- } else
- // A type projection like X#Y can get by the stable check if the
- // prefix is singleton-bounded, so peek at the tree too.
- tpt match {
- case SelectFromTypeTree(qual, _) if !isSingleType(qual.tpe) => errorNotClass(tpt)
- case _ => true
- }
- else
- true
- case ErrorType => true
- case PolyType(_, restpe) => check(restpe)
- case ExistentialType(_, restpe) if existentialOK => check(restpe)
- case AnnotatedType(_, underlying, _) => check(underlying)
- case t => errorNotClass(t)
+ def checkClassType(tpt: Tree): Boolean = {
+ val tpe = unwrapToClass(tpt.tpe)
+ isNonRefinementClassType(tpe) || errorNotClass(tpt, tpe)
+ }
+
+ /** Check that `tpt` refers to a class type with a stable prefix. */
+ def checkStablePrefixClassType(tpt: Tree): Boolean = {
+ val tpe = unwrapToStableClass(tpt.tpe)
+ def prefixIsStable = {
+ def checkPre = tpe match {
+ case TypeRef(pre, _, _) => pre.isStable || errorNotStable(tpt, pre)
+ case _ => false
+ }
+ // A type projection like X#Y can get by the stable check if the
+ // prefix is singleton-bounded, so peek at the tree too.
+ def checkTree = tpt match {
+ case SelectFromTypeTree(qual, _) => isSingleType(qual.tpe) || errorNotClass(tpt, tpe)
+ case _ => true
+ }
+ checkPre && checkTree
}
- check(tpt.tpe)
+
+ ( (isNonRefinementClassType(tpe) || errorNotClass(tpt, tpe))
+ && (isPastTyper || prefixIsStable)
+ )
}
/** Check that type <code>tp</code> is not a subtype of itself.
@@ -643,13 +652,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
}
- private def isNarrowable(tpe: Type): Boolean = tpe match {
+ private def isNarrowable(tpe: Type): Boolean = unwrapWrapperTypes(tpe) match {
case TypeRef(_, _, _) | RefinedType(_, _) => true
- case ExistentialType(_, tpe1) => isNarrowable(tpe1)
- case AnnotatedType(_, tpe1, _) => isNarrowable(tpe1)
- case PolyType(_, tpe1) => isNarrowable(tpe1)
- case NullaryMethodType(tpe1) => isNarrowable(tpe1)
- case _ => !phase.erasedTypes
+ case _ => !phase.erasedTypes
}
/**
@@ -909,8 +914,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def apply(tp: Type) = mapOver(tp) match {
case TypeRef(NoPrefix, tpSym, Nil) if variance != 0 && tpSym.isTypeParameterOrSkolem && tpSym.owner.isTerm =>
val bounds = if (variance == 1) TypeBounds.upper(tpSym.tpe) else TypeBounds.lower(tpSym.tpe)
- val skolem = context.owner.newExistentialSkolem(tpSym, tpSym, unit.freshTypeName("?"+tpSym.name), bounds)
- // println("mapping "+ tpSym +" to "+ skolem + " : "+ bounds +" -- pt= "+ pt)
+ // origin must be the type param so we can deskolemize
+ val skolem = context.owner.newGADTSkolem(unit.freshTypeName("?"+tpSym.name), tpSym, bounds)
+ // println("mapping "+ tpSym +" to "+ skolem + " : "+ bounds +" -- pt= "+ pt +" in "+ context.owner +" at "+ context.tree )
skolems += skolem
skolem.tpe
case tp1 => tp1
@@ -928,9 +934,19 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
freeVars foreach ctorContext.scope.enter
newTyper(ctorContext).infer.inferConstructorInstance(tree1, clazz.typeParams, ptSafe)
- // tree1's type-slack skolems will be deskolemized (to the method type parameter skolems)
- // once the containing CaseDef has been type checked (see typedCase)
- tree1
+ // simplify types without losing safety,
+ // so that error messages don't unnecessarily refer to skolems
+ val extrapolate = new ExistentialExtrapolation(freeVars) extrapolate (_: Type)
+ val extrapolated = tree1.tpe match {
+ case MethodType(ctorArgs, res) => // ctorArgs are actually in a covariant position, since this is the type of the subpatterns of the pattern represented by this Apply node
+ ctorArgs foreach (p => p.info = extrapolate(p.info)) // no need to clone, this is OUR method type
+ copyMethodType(tree1.tpe, ctorArgs, extrapolate(res))
+ case tp => tp
+ }
+
+ // once the containing CaseDef has been type checked (see typedCase),
+ // tree1's remaining type-slack skolems will be deskolemized (to the method type parameter skolems)
+ tree1 setType extrapolated
} else {
tree
}
@@ -1095,7 +1111,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val found = tree.tpe
val req = pt
if (!found.isErroneous && !req.isErroneous) {
- if (!context.reportErrors && isPastTyper && req.existentialSkolems.nonEmpty) {
+ if (!context.reportErrors && isPastTyper && req.skolemsExceptMethodTypeParams.nonEmpty) {
// Ignore type errors raised in later phases that are due to mismatching types with existential skolems
// We have lift crashing in 2.9 with an adapt failure in the pattern matcher.
// Here's my hypothsis why this happens. The pattern matcher defines a variable of type
@@ -1112,7 +1128,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
//
// val x = expr
context.unit.warning(tree.pos, "recovering from existential Skolem type error in tree \n" + tree + "\nwith type " + tree.tpe + "\n expected type = " + pt + "\n context = " + context.tree)
- adapt(tree, mode, deriveTypeWithWildcards(pt.existentialSkolems)(pt))
+ adapt(tree, mode, deriveTypeWithWildcards(pt.skolemsExceptMethodTypeParams)(pt))
} else {
// create an actual error
AdaptTypeError(tree, found, req)
@@ -1147,6 +1163,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val qtpe = qual.tpe.widen
( !isPastTyper
&& qual.isTerm
+ && !qual.isInstanceOf[Super]
&& ((qual.symbol eq null) || !qual.symbol.isTerm || qual.symbol.isValue)
&& !qtpe.isError
&& !qtpe.typeSymbol.isBottomClass
@@ -1162,12 +1179,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
)
}
- def adaptToMember(qual: Tree, searchTemplate: Type): Tree =
- adaptToMember(qual, searchTemplate, true, true)
- def adaptToMember(qual: Tree, searchTemplate: Type, reportAmbiguous: Boolean): Tree =
- adaptToMember(qual, searchTemplate, reportAmbiguous, true)
-
- def adaptToMember(qual: Tree, searchTemplate: Type, reportAmbiguous: Boolean, saveErrors: Boolean): Tree = {
+ def adaptToMember(qual: Tree, searchTemplate: Type, reportAmbiguous: Boolean = true, saveErrors: Boolean = true): Tree = {
if (isAdaptableWithView(qual)) {
qual.tpe.widen.normalize match {
case et: ExistentialType =>
@@ -1273,8 +1285,6 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
unit.error(clazz.pos, "value class may not be a "+
(if (clazz.owner.isTerm) "local class" else "member of another class"))
val constr = clazz.primaryConstructor
- if ((constr hasFlag (PRIVATE | PROTECTED)) || constr.privateWithin != NoSymbol)
- unit.error(constr.pos, "value class must have public primary constructor")
clazz.info.decls.toList.filter(acc => acc.isMethod && (acc hasFlag PARAMACCESSOR)) match {
case List(acc) =>
def isUnderlyingAcc(sym: Symbol) =
@@ -1433,7 +1443,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def validateParentClass(parent: Tree, superclazz: Symbol) {
if (!parent.isErrorTyped) {
val psym = parent.tpe.typeSymbol.initialize
- checkClassType(parent, false, true)
+ checkStablePrefixClassType(parent)
if (psym != superclazz) {
if (psym.isTrait) {
val ps = psym.info.parents
@@ -2112,26 +2122,192 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// body1 = checkNoEscaping.locals(context.scope, pt, body1)
val treeWithSkolems = treeCopy.CaseDef(cdef, pat1, guard1, body1) setType body1.tpe
- // undo adaptConstrPattern's evil deeds, as they confuse the old pattern matcher
- // TODO: Paul, can we do the deskolemization lazily in the old pattern matcher
- object deskolemizeOnce extends TypeMap {
- def apply(tp: Type): Type = mapOver(tp) match {
- case TypeRef(pre, sym, args) if sym.isExistentialSkolem && sym.deSkolemize.isSkolem && sym.deSkolemize.owner.isTerm =>
- typeRef(NoPrefix, sym.deSkolemize, args)
- case tp1 => tp1
- }
- }
-
- new TypeMapTreeSubstituter(deskolemizeOnce).traverse(treeWithSkolems)
+ new TypeMapTreeSubstituter(deskolemizeGADTSkolems).traverse(treeWithSkolems)
treeWithSkolems // now without skolems, actually
}
+ // undo adaptConstrPattern's evil deeds, as they confuse the old pattern matcher
+ // the flags are used to avoid accidentally deskolemizing unrelated skolems of skolems
+ object deskolemizeGADTSkolems extends TypeMap {
+ def apply(tp: Type): Type = mapOver(tp) match {
+ case TypeRef(pre, sym, args) if sym.isGADTSkolem =>
+ typeRef(NoPrefix, sym.deSkolemize, args)
+ case tp1 => tp1
+ }
+ }
+
def typedCases(cases: List[CaseDef], pattp: Type, pt: Type): List[CaseDef] =
cases mapConserve { cdef =>
newTyper(context.makeNewScope(cdef, context.owner)).typedCase(cdef, pattp, pt)
}
+ def adaptCase(cdef: CaseDef, mode: Int, tpe: Type): CaseDef = deriveCaseDef(cdef)(adapt(_, mode, tpe))
+
+ def prepareTranslateMatch(selector0: Tree, cases: List[CaseDef], mode: Int, resTp: Type) = {
+ val (selector, doTranslation) = selector0 match {
+ case Annotated(Ident(nme.synthSwitch), selector) => (selector, false)
+ case s => (s, true)
+ }
+ val selector1 = checkDead(typed(selector, EXPRmode | BYVALmode, WildcardType))
+ val selectorTp = packCaptured(selector1.tpe.widen)
+
+ val casesTyped = typedCases(cases, selectorTp, resTp)
+ val caseTypes = casesTyped map (c => packedType(c, context.owner).deconst)
+ val (ownType, needAdapt) = if (isFullyDefined(resTp)) (resTp, false) else weakLub(caseTypes)
+
+ val casesAdapted = if (!needAdapt) casesTyped else casesTyped map (adaptCase(_, mode, ownType))
+
+ (selector1, selectorTp, casesAdapted, ownType, doTranslation)
+ }
+
+ def translateMatch(selector1: Tree, selectorTp: Type, casesAdapted: List[CaseDef], ownType: Type, doTranslation: Boolean, matchFailGen: Option[Tree => Tree] = None) = {
+ def repeatedToSeq(tp: Type): Type = (tp baseType RepeatedParamClass) match {
+ case TypeRef(_, RepeatedParamClass, args) => appliedType(SeqClass.typeConstructor, args)
+ case _ => tp
+ }
+
+ if (!doTranslation) { // a switch
+ Match(selector1, casesAdapted) setType ownType // setType of the Match to avoid recursing endlessly
+ } else {
+ val scrutType = repeatedToSeq(elimAnonymousClass(selectorTp))
+ // we've packed the type for each case in prepareTranslateMatch so that if all cases have the same existential case, we get a clean lub
+ // here, we should open up the existential again
+ // relevant test cases: pos/existentials-harmful.scala, pos/gadt-gilles.scala, pos/t2683.scala, pos/virtpatmat_exist4.scala
+ MatchTranslator(this).translateMatch(selector1, casesAdapted, repeatedToSeq(ownType.skolemizeExistential(context.owner, context.tree)), scrutType, matchFailGen)
+ }
+ }
+
+ def typedMatchAnonFun(tree: Tree, cases: List[CaseDef], mode: Int, pt0: Type, selOverride: Option[(List[ValDef], Tree)] = None) = {
+ val pt = deskolemizeGADTSkolems(pt0)
+ val targs = pt.normalize.typeArgs
+ val arity = if (isFunctionType(pt)) targs.length - 1 else 1 // TODO pt should always be a (Partial)Function, right?
+ val ptRes = if (targs.isEmpty) WildcardType else targs.last // may not be fully defined
+
+ val isPartial = pt.typeSymbol == PartialFunctionClass
+ val anonClass = context.owner.newAnonymousFunctionClass(tree.pos)
+ val funThis = This(anonClass)
+ val serialVersionUIDAnnotation = AnnotationInfo(SerialVersionUIDAttr.tpe, List(Literal(Constant(0))), List())
+
+ anonClass addAnnotation serialVersionUIDAnnotation
+
+ def deriveFormals =
+ selOverride match {
+ case None if targs.isEmpty => Nil
+ case None => targs.init // is there anything we can do if targs.isEmpty??
+ case Some((vparams, _)) =>
+ vparams map {p => if(p.tpt.tpe == null) typedType(p.tpt).tpe else p.tpt.tpe}
+ }
+
+ def mkParams(methodSym: Symbol, formals: List[Type] = deriveFormals) = {
+ selOverride match {
+ case None if targs.isEmpty => MissingParameterTypeAnonMatchError(tree, pt); (Nil, EmptyTree)
+ case None =>
+ val ps = methodSym newSyntheticValueParams formals // is there anything we can do if targs.isEmpty??
+ val ids = ps map (p => Ident(p.name))
+ val sel = atPos(tree.pos.focusStart) { if (arity == 1) ids.head else gen.mkTuple(ids) }
+ (ps, sel)
+ case Some((vparams, sel)) =>
+ val newParamSyms = (vparams, formals).zipped map {(p, tp) =>
+ methodSym.newValueParameter(p.name, focusPos(p.pos), SYNTHETIC) setInfo tp
+ }
+
+ (newParamSyms, sel.duplicate)
+ }
+ }
+
+ import CODE._
+
+ // need to duplicate the cases before typing them to generate the apply method, or the symbols will be all messed up
+ val casesTrue = if (isPartial) cases map (c => deriveCaseDef(c)(x => TRUE_typed).duplicate) else Nil
+
+ def applyMethod = {
+ // rig the show so we can get started typing the method body -- later we'll correct the infos...
+ anonClass setInfo ClassInfoType(List(ObjectClass.tpe, pt, SerializableClass.tpe), newScope, anonClass)
+ val methodSym = anonClass.newMethod(nme.apply, tree.pos, FINAL)
+ val (paramSyms, selector) = mkParams(methodSym)
+
+ if (selector eq EmptyTree) EmptyTree
+ else {
+ methodSym setInfoAndEnter MethodType(paramSyms, AnyClass.tpe)
+
+ val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it)
+ paramSyms foreach (methodBodyTyper.context.scope enter _)
+
+ val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, cases, mode, ptRes)
+
+ val methFormals = paramSyms map (_.tpe)
+ val parents = List(appliedType(AbstractFunctionClass(arity).typeConstructor, methFormals :+ resTp), SerializableClass.tpe)
+
+ anonClass setInfo ClassInfoType(parents, newScope, anonClass)
+ methodSym setInfoAndEnter MethodType(paramSyms, resTp)
+
+ DefDef(methodSym, methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation))
+ }
+ }
+
+ // def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 =
+ def applyOrElseMethodDef = {
+ // rig the show so we can get started typing the method body -- later we'll correct the infos...
+ // targs were type arguments for PartialFunction, so we know they will work for AbstractPartialFunction as well
+ def parents(targs: List[Type]) = List(appliedType(AbstractPartialFunctionClass.typeConstructor, targs), SerializableClass.tpe)
+
+ anonClass setInfo ClassInfoType(parents(targs), newScope, anonClass)
+ val methodSym = anonClass.newMethod(nme.applyOrElse, tree.pos, FINAL | OVERRIDE)
+
+ // create the parameter that corresponds to the function's parameter
+ val List(argTp) = deriveFormals
+ val A1 = methodSym newTypeParameter(newTypeName("A1")) setInfo TypeBounds.upper(argTp)
+ val (List(x), selector) = mkParams(methodSym, List(A1.tpe))
+
+ if (selector eq EmptyTree) EmptyTree
+ else {
+ // applyOrElse's default parameter:
+ val B1 = methodSym newTypeParameter(newTypeName("B1")) setInfo TypeBounds.empty //lower(resTp)
+ val default = methodSym newValueParameter(newTermName("default"), focusPos(tree.pos), SYNTHETIC) setInfo functionType(List(A1.tpe), B1.tpe)
+
+ val paramSyms = List(x, default)
+ methodSym setInfoAndEnter polyType(List(A1, B1), MethodType(paramSyms, B1.tpe))
+
+ val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it)
+ paramSyms foreach (methodBodyTyper.context.scope enter _)
+
+ val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, cases, mode, ptRes)
+
+ anonClass setInfo ClassInfoType(parents(List(argTp, resTp)), newScope, anonClass)
+ B1 setInfo TypeBounds.lower(resTp)
+ anonClass.info.decls enter methodSym // methodSym's info need not change (B1's bound has been updated instead)
+
+ // use applyOrElse's first parameter since the scrut's type has been widened
+ def doDefault(scrut_ignored: Tree) = REF(default) APPLY (REF(x))
+
+ val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, B1.tpe, doTranslation, Some(doDefault))
+
+ DefDef(methodSym, body)
+ }
+ }
+
+ def isDefinedAtMethod = {
+ val methodSym = anonClass.newMethod(nme.isDefinedAt, tree.pos, FINAL)
+ val (paramSyms, selector) = mkParams(methodSym)
+ if (selector eq EmptyTree) EmptyTree
+ else {
+ val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it)
+ paramSyms foreach (methodBodyTyper.context.scope enter _)
+ methodSym setInfoAndEnter MethodType(paramSyms, BooleanClass.tpe)
+
+ val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, casesTrue, mode, BooleanClass.tpe)
+ val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation, Some(scrutinee => FALSE_typed))
+
+ DefDef(methodSym, body)
+ }
+ }
+
+ val members = if (!isPartial) List(applyMethod) else List(applyOrElseMethodDef, isDefinedAtMethod)
+ if (members.head eq EmptyTree) setError(tree)
+ else typed(Block(List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, tree.pos)), New(anonClass.tpe)), mode, pt)
+ }
+
/**
* @param fun ...
* @param mode ...
@@ -2144,14 +2320,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
return MaxFunctionArityError(fun)
def decompose(pt: Type): (Symbol, List[Type], Type) =
- if ((isFunctionType(pt)
- ||
- pt.typeSymbol == PartialFunctionClass &&
- numVparams == 1 && fun.body.isInstanceOf[Match])
- && // see bug901 for a reason why next conditions are needed
- (pt.normalize.typeArgs.length - 1 == numVparams
- ||
- fun.vparams.exists(_.tpt.isEmpty)))
+ if ((isFunctionType(pt) || (pt.typeSymbol == PartialFunctionClass && numVparams == 1 && fun.body.isInstanceOf[Match])) && // see bug901 for a reason why next conditions are needed
+ ( pt.normalize.typeArgs.length - 1 == numVparams
+ || fun.vparams.exists(_.tpt.isEmpty)
+ ))
(pt.typeSymbol, pt.normalize.typeArgs.init, pt.normalize.typeArgs.last)
else
(FunctionClass(numVparams), fun.vparams map (x => NoType), WildcardType)
@@ -2160,7 +2332,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (argpts.lengthCompare(numVparams) != 0)
WrongNumberOfParametersError(fun, argpts)
else {
- val vparamSyms = map2(fun.vparams, argpts) { (vparam, argpt) =>
+ foreach2(fun.vparams, argpts) { (vparam, argpt) =>
if (vparam.tpt.isEmpty) {
vparam.tpt.tpe =
if (isFullyDefined(argpt)) argpt
@@ -2184,22 +2356,32 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
if (!vparam.tpt.pos.isDefined) vparam.tpt setPos vparam.pos.focus
}
- enterSym(context, vparam)
- if (context.retyping) context.scope enter vparam.symbol
- vparam.symbol
}
- val vparams = fun.vparams mapConserve (typedValDef)
-// for (vparam <- vparams) {
-// checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); ()
-// }
- val body1 = typed(fun.body, respt)
- val formals = vparamSyms map (_.tpe)
- val restpe = packedType(body1, fun.symbol).deconst.resultType
- val funtpe = typeRef(clazz.tpe.prefix, clazz, formals :+ restpe)
-// body = checkNoEscaping.locals(context.scope, restpe, body)
- treeCopy.Function(fun, vparams, body1).setType(funtpe)
- }
+ fun.body match {
+ case Match(sel, cases) if opt.virtPatmat =>
+ // go to outer context -- must discard the context that was created for the Function since we're discarding the function
+ // thus, its symbol, which serves as the current context.owner, is not the right owner
+ // you won't know you're using the wrong owner until lambda lift crashes (unless you know better than to use the wrong owner)
+ newTyper(context.outer).typedMatchAnonFun(fun, cases, mode, pt, Some((fun.vparams, sel)))
+ case _ =>
+ val vparamSyms = fun.vparams map { vparam =>
+ enterSym(context, vparam)
+ if (context.retyping) context.scope enter vparam.symbol
+ vparam.symbol
+ }
+ val vparams = fun.vparams mapConserve (typedValDef)
+ // for (vparam <- vparams) {
+ // checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); ()
+ // }
+ val formals = vparamSyms map (_.tpe)
+ val body1 = typed(fun.body, respt)
+ val restpe = packedType(body1, fun.symbol).deconst.resultType
+ val funtpe = typeRef(clazz.tpe.prefix, clazz, formals :+ restpe)
+ // body = checkNoEscaping.locals(context.scope, restpe, body)
+ treeCopy.Function(fun, vparams, body1).setType(funtpe)
+ }
+ }
}
def typedRefinement(stats: List[Tree]) {
@@ -3176,7 +3358,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
def typedClassOf(tree: Tree, tpt: Tree, noGen: Boolean = false) =
- if (!checkClassType(tpt, true, false) && noGen) tpt
+ if (!checkClassType(tpt) && noGen) tpt
else atPos(tree.pos)(gen.mkClassOf(tpt.tpe))
protected def typedExistentialTypeTree(tree: ExistentialTypeTree, mode: Int): Tree = {
@@ -3410,7 +3592,18 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
} else {
var thenp1 = typed(thenp, pt)
var elsep1 = typed(elsep, pt)
- val (owntype, needAdapt) = ptOrLub(List(thenp1.tpe, elsep1.tpe))
+
+ lazy val thenTp = packedType(thenp1, context.owner)
+ lazy val elseTp = packedType(elsep1, context.owner)
+ val (owntype, needAdapt) =
+ // in principle we should pack the types of each branch before lubbing, but lub doesn't really work for existentials anyway
+ // in the special (though common) case where the types are equal, it pays to pack before comparing
+ // especially virtpatmat needs more aggressive unification of skolemized types
+ // this breaks src/library/scala/collection/immutable/TrieIterator.scala
+ if (opt.virtPatmat && !isPastTyper && thenTp =:= elseTp) (thenp1.tpe, false) // use unpacked type
+ // TODO: skolemize (lub of packed types) when that no longer crashes on files/pos/t4070b.scala
+ else ptOrLub(List(thenp1.tpe, elsep1.tpe))
+
if (needAdapt) { //isNumericValueType(owntype)) {
thenp1 = adapt(thenp1, mode, owntype)
elsep1 = adapt(elsep1, mode, owntype)
@@ -3420,7 +3613,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
def typedMatch(tree: Tree, selector: Tree, cases: List[CaseDef]): Tree = {
- if (selector == EmptyTree) {
+ if (opt.virtPatmat && !isPastTyper) {
+ if (selector ne EmptyTree) {
+ val (selector1, selectorTp, casesAdapted, ownType, doTranslation) = prepareTranslateMatch(selector, cases, mode, pt)
+ typed(translateMatch(selector1, selectorTp, casesAdapted, ownType, doTranslation), mode, pt)
+ } else typedMatchAnonFun(tree, cases, mode, pt)
+ } else if (selector == EmptyTree) {
val arity = if (isFunctionType(pt)) pt.normalize.typeArgs.length - 1 else 1
val params = for (i <- List.range(0, arity)) yield
atPos(tree.pos.focusStart) {
@@ -3434,32 +3632,11 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
} else {
val selector1 = checkDead(typed(selector, EXPRmode | BYVALmode, WildcardType))
var cases1 = typedCases(cases, packCaptured(selector1.tpe.widen), pt)
-
- if (isPastTyper || !opt.virtPatmat) {
- val (owntype, needAdapt) = ptOrLub(cases1 map (_.tpe))
- if (needAdapt) {
- cases1 = cases1 map (adaptCase(_, owntype))
- }
- treeCopy.Match(tree, selector1, cases1) setType owntype
- } else { // don't run translator after typers (see comments in PatMatVirtualiser)
- val (owntype0, needAdapt) = ptOrLub(cases1 map (x => repackExistential(x.tpe)))
- val owntype = elimAnonymousClass(owntype0)
- if (needAdapt) cases1 = cases1 map (adaptCase(_, owntype))
-
- (MatchTranslator(this)).translateMatch(selector1, cases1, owntype) match {
- case Block(vd :: Nil, tree@Match(selector, cases)) =>
- val selector1 = checkDead(typed(selector, EXPRmode | BYVALmode, WildcardType))
- var cases1 = typedCases(cases, packCaptured(selector1.tpe.widen), pt)
- val (owntype, needAdapt) = ptOrLub(cases1 map (_.tpe))
- if (needAdapt)
- cases1 = cases1 map (adaptCase(_, owntype))
- typed(Block(vd :: Nil, treeCopy.Match(tree, selector1, cases1) setType owntype))
- case translated =>
- // TODO: get rid of setType owntype -- it should all typecheck
- // must call typed, not typed1, or we overflow the stack when emitting switches
- typed(translated, mode, WildcardType) setType owntype
- }
+ val (owntype, needAdapt) = ptOrLub(cases1 map (_.tpe))
+ if (needAdapt) {
+ cases1 = cases1 map (adaptCase(_, mode, owntype))
}
+ treeCopy.Match(tree, selector1, cases1) setType owntype
}
}
@@ -3493,7 +3670,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def typedNew(tpt: Tree) = {
val tpt1 = {
val tpt0 = typedTypeConstructor(tpt)
- if (checkClassType(tpt0, false, true))
+ if (checkStablePrefixClassType(tpt0))
if (tpt0.hasSymbol && !tpt0.symbol.typeParams.isEmpty) {
context.undetparams = cloneSymbols(tpt0.symbol.typeParams)
TypeTree().setOriginal(tpt0)
@@ -4011,7 +4188,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
var defEntry: ScopeEntry = null // the scope entry of defSym, if defined in a local scope
var cx = startingIdentContext
- while (defSym == NoSymbol && cx != NoContext) {
+ while (defSym == NoSymbol && cx != NoContext && (cx.scope ne null)) { // cx.scope eq null arises during FixInvalidSyms in Duplicators
// !!! Shouldn't the argument to compileSourceFor be cx, not context?
// I can't tell because those methods do nothing in the standard compiler,
// presumably they are overridden in the IDE.
@@ -4229,9 +4406,6 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
}
- def adaptCase(cdef: CaseDef, tpe: Type): CaseDef =
- deriveCaseDef(cdef)(adapt(_, mode, tpe))
-
// begin typed1
val sym: Symbol = tree.symbol
if ((sym ne null) && (sym ne NoSymbol)) sym.initialize
@@ -4340,7 +4514,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val (owntype, needAdapt) = ptOrLub(block1.tpe :: (catches1 map (_.tpe)))
if (needAdapt) {
block1 = adapt(block1, mode, owntype)
- catches1 = catches1 map (adaptCase(_, owntype))
+ catches1 = catches1 map (adaptCase(_, mode, owntype))
}
if(!isPastTyper && opt.virtPatmat) {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
index cc272b7b8d..4f5b6868ae 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
@@ -45,6 +45,11 @@ trait Unapplies extends ast.TreeDSL
case BooleanClass => Nil
case OptionClass | SomeClass =>
val prod = tp.typeArgs.head
+// the spec doesn't allow just any subtype of Product, it *must* be TupleN[...] -- see run/virtpatmat_extends_product.scala
+// this breaks plenty of stuff, though...
+// val targs =
+// if (isTupleType(prod)) getProductArgs(prod)
+// else List(prod)
val targs = getProductArgs(prod)
if (targs.isEmpty || targs.tail.isEmpty) List(prod) // special n == 0 || n == 1
diff --git a/src/compiler/scala/tools/nsc/util/Position.scala b/src/compiler/scala/tools/nsc/util/Position.scala
index 53c767be20..bc74717366 100644
--- a/src/compiler/scala/tools/nsc/util/Position.scala
+++ b/src/compiler/scala/tools/nsc/util/Position.scala
@@ -33,6 +33,16 @@ object Position {
}
}
+/**
+ * A tree does not directly store a Position. It stores a TreeAnnotation, which /typically/ is a Position.
+ *
+ * A TreeAnnotion may encompass more than just a Position, though, depending on the exact subclass of TreeAnnotation.
+ */
+trait TreeAnnotation {
+ def pos: Position
+}
+
+
/** The Position class and its subclasses represent positions of ASTs and symbols.
* Except for NoPosition and FakePos, every position refers to a SourceFile
* and to an offset in the sourcefile (its `point`). For batch compilation,
@@ -77,7 +87,8 @@ object Position {
* pos.makeTransparent converts an opaque range position into a transparent one.
* returns all other positions unchanged.
*/
-trait Position {
+trait Position extends TreeAnnotation {
+ def pos: Position = this
/** An optional value containing the source file referred to by this position, or
* None if not defined.
diff --git a/src/compiler/scala/tools/util/color/CString.scala b/src/compiler/scala/tools/util/color/CString.scala
index d0785eaeff..fa57229f09 100644
--- a/src/compiler/scala/tools/util/color/CString.scala
+++ b/src/compiler/scala/tools/util/color/CString.scala
@@ -11,18 +11,27 @@ final class CString(val uncolorized: String, val colorized: String) {
def visibleLength = uncolorized.length
def colorizedLength = colorized.length
def show() = Console println colorized
- def bytes() = colorized map (ch => ch.toByte)
- def > = show()
+ def bytes() = colorized map (_.toByte)
+ def >() = show()
def append(x: CString): CString = new CString(uncolorized + x.uncolorized, colorized + x.colorized)
def +(other: CString): CString = this append other
+
override def toString = colorized
}
class CStringOps(str: String) {
- /** Enables for example
+ /** String to String operation.
* println("foo" in Red)
- * println("foo" in Magenta.bright)
+ * println("bar" in Magenta.bright)
+ */
+ def in(ansi: Ansi): String = ansi colorize str
+
+ /** Gave in to one bit of punctuation, because everyone adds
+ * strings with '+' and we need something which higher precedence
+ * for it to be at all satisfying.
+ *
+ * "foo" %> Red + "bar" %> Magenta.bright
*/
- def in(ansi: Ansi): CString = new CString(str, ansi colorize str)
+ def %>(ansi: Ansi): CString = new CString(str, in(ansi))
}
diff --git a/src/compiler/scala/tools/util/color/package.scala b/src/compiler/scala/tools/util/color/package.scala
index 7c7c7dab74..3b3e85751e 100644
--- a/src/compiler/scala/tools/util/color/package.scala
+++ b/src/compiler/scala/tools/util/color/package.scala
@@ -18,4 +18,5 @@ package object color {
case x: AnsiForeground => x.flip
}
implicit def implicitCStringOps(str: String): CStringOps = new CStringOps(str)
+ implicit def implicitCString(str: String): CString = new CString(str, str)
}
diff --git a/src/library/scala/Function.scala b/src/library/scala/Function.scala
index 4a10b65735..9fa56a332f 100644
--- a/src/library/scala/Function.scala
+++ b/src/library/scala/Function.scala
@@ -29,6 +29,7 @@ object Function {
/** Turns a function `A => Option[B]` into a `PartialFunction[A, B]`.
*
+ * TODO: check if the paragraph below is still correct
* '''Important note''': this transformation implies the original function
* will be called 2 or more times on each logical invocation, because the
* only way to supply an implementation of `isDefinedAt` is to call the
@@ -39,11 +40,7 @@ object Function {
* f returns `Some(_)` and undefined where `f` returns `None`.
* @see [[scala.PartialFunction#lift]]
*/
- def unlift[T, R](f: T => Option[R]): PartialFunction[T, R] = new runtime.AbstractPartialFunction[T, R] {
- def apply(x: T): R = f(x).get
- def _isDefinedAt(x: T): Boolean = f(x).isDefined
- override def lift: T => Option[R] = f
- }
+ def unlift[T, R](f: T => Option[R]): PartialFunction[T, R] = PartialFunction.unlifted(f)
/** Uncurrying for functions of arity 2. This transforms a unary function
* returning another unary function into a function of arity 2.
diff --git a/src/library/scala/PartialFunction.scala b/src/library/scala/PartialFunction.scala
index 3c5d6d0d23..7154b8da34 100644
--- a/src/library/scala/PartialFunction.scala
+++ b/src/library/scala/PartialFunction.scala
@@ -8,6 +8,7 @@
package scala
+
/** A partial function of type `PartialFunction[A, B]` is a unary function
* where the domain does not necessarily include all values of type `A`.
* The function `isDefinedAt` allows to test dynamically if a value is in
@@ -43,10 +44,11 @@ package scala
* }}}
*
*
- * @author Martin Odersky
+ * @author Martin Odersky, Pavel Pavlov, Adriaan Moors
* @version 1.0, 16/07/2003
*/
-trait PartialFunction[-A, +B] extends (A => B) {
+trait PartialFunction[-A, +B] extends (A => B) { self =>
+ import PartialFunction._
/** Checks if a value is contained in the function's domain.
*
@@ -55,10 +57,6 @@ trait PartialFunction[-A, +B] extends (A => B) {
*/
def isDefinedAt(x: A): Boolean
- //protected def missingCase[A1 <: A, B1 >: B]: PartialFunction[A1, B1] = PartialFunction.empty
-
- protected def missingCase(x: A): B = throw new MatchError(x)
-
/** Composes this partial function with a fallback partial function which
* gets applied where this partial function is not defined.
*
@@ -70,16 +68,8 @@ trait PartialFunction[-A, +B] extends (A => B) {
* takes `x` to `this(x)` where `this` is defined, and to `that(x)` where it is not.
*/
def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]) : PartialFunction[A1, B1] =
- new runtime.AbstractPartialFunction[A1, B1] {
- def _isDefinedAt(x: A1): Boolean =
- PartialFunction.this.isDefinedAt(x) || that.isDefinedAt(x)
- def apply(x: A1): B1 =
- if (PartialFunction.this.isDefinedAt(x)) PartialFunction.this.apply(x)
- else that.apply(x)
- }
-
- def orElseFast[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]) : PartialFunction[A1, B1] =
- orElse(that)
+ new OrElse[A1, B1] (this, that)
+ //TODO: why not overload it with orElse(that: F1): F1?
/** Composes this partial function with a transformation function that
* gets applied to results of this partial function.
@@ -88,9 +78,9 @@ 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) : PartialFunction[A, C] = new runtime.AbstractPartialFunction[A, C] {
- def _isDefinedAt(x: A): Boolean = PartialFunction.this.isDefinedAt(x)
- def apply(x: A): C = k(PartialFunction.this.apply(x))
+ override def andThen[C](k: B => C) : PartialFunction[A, C] = new PartialFunction[A, C] {
+ def isDefinedAt(x: A): Boolean = self isDefinedAt x
+ def apply(x: A): C = k(self(x))
}
/** Turns this partial function into an plain function returning an `Option` result.
@@ -98,9 +88,30 @@ trait PartialFunction[-A, +B] extends (A => B) {
* @return a function that takes an argument `x` to `Some(this(x))` if `this`
* is defined for `x`, and to `None` otherwise.
*/
- def lift: A => Option[B] = new (A => Option[B]) {
- def apply(x: A): Option[B] = if (isDefinedAt(x)) Some(PartialFunction.this.apply(x)) else None
- }
+ def lift: A => Option[B] = new Lifted(this)
+
+ /**
+ * TODO: comment
+ * @since 2.10
+ */
+ def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 =
+ if (isDefinedAt(x)) apply(x) else default(x)
+
+ /**
+ * TODO: comment
+ * @since 2.10
+ */
+ def run[U](x: A)(action: B => U): Boolean =
+ applyOrElse(x, fallbackToken) match {
+ case FallbackToken => false
+ case z => action(z); true
+ }
+
+ /**
+ * TODO: comment
+ * @since 2.10
+ */
+ def runWith[U](action: B => U): A => Boolean = { x => run(x)(action) }
}
/** A few handy operations which leverage the extra bit of information
@@ -119,14 +130,73 @@ trait PartialFunction[-A, +B] extends (A => B) {
* @since 2.8
*/
object PartialFunction {
- private[this] final val empty_pf: PartialFunction[Any, Nothing] = new runtime.AbstractPartialFunction[Any, Nothing] {
- def _isDefinedAt(x: Any) = false
- override def isDefinedAt(x: Any) = false
- def apply(x: Any): Nothing = throw new MatchError(x)
- override def orElse[A1, B1](that: PartialFunction[A1, B1]): PartialFunction[A1, B1] = that
- override def orElseFast[A1, B1](that: PartialFunction[A1, B1]): PartialFunction[A1, B1] = that
- override def lift = (x: Any) => None
+ /** Composite function produced by `PartialFunction#orElse` method
+ */
+ private final class OrElse[-A, +B] (f1: PartialFunction[A, B], f2: PartialFunction[A, B]) extends PartialFunction[A, B] {
+ def isDefinedAt(x: A) = f1.isDefinedAt(x) || f2.isDefinedAt(x)
+
+ def apply(x: A): B = f1.applyOrElse(x, f2)
+
+ override def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 =
+ f1.applyOrElse(x, fallbackToken) match {
+ case FallbackToken => f2.applyOrElse(x, default)
+ case z => z
+ }
+
+ override def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]) =
+ new OrElse[A1, B1] (f1, f2 orElse that)
+
+ override def andThen[C](k: B => C) =
+ new OrElse[A, C] (f1 andThen k, f2 andThen k)
}
+
+ private[scala] lazy val FallbackToken: PartialFunction[Any, PartialFunction[Any, Nothing]] = { case _ => FallbackToken.asInstanceOf[PartialFunction[Any, Nothing]] }
+ private[scala] final def fallbackToken[B] = FallbackToken.asInstanceOf[PartialFunction[Any, B]]
+ //TODO: check generated code for PF literal here
+
+ private[scala] final class Lifted[-A, +B] (val pf: PartialFunction[A, B])
+ extends runtime.AbstractFunction1[A, Option[B]] {
+
+ def apply(x: A): Option[B] = pf.applyOrElse(x, fallbackToken) match {
+ case FallbackToken => None
+ case z => Some(z)
+ }
+ }
+
+ private final class Unlifted[A, B] (f: A => Option[B]) extends runtime.AbstractPartialFunction[A, B] {
+ def isDefinedAt(x: A): Boolean = f(x).isDefined
+ override def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 =
+ f(x) getOrElse default(x) //TODO: check generated code and inline getOrElse if needed
+ override def lift = f
+ }
+
+ private[scala] def unlifted[A, B](f: A => Option[B]): PartialFunction[A, B] = f match {
+ case lf: Lifted[A, B] => lf.pf
+ case ff => new Unlifted(ff)
+ }
+
+ /** Converts ordinary function to partial one
+ * @since 2.10
+ */
+ //TODO: check generated code for PF literal here
+ def apply[A, B](f: A => B): PartialFunction[A, B] = { case x => f(x) }
+
+ private[this] final val constFalse: Any => Boolean = { _ => false}
+
+ private[this] final val empty_pf: PartialFunction[Any, Nothing] = new PartialFunction[Any, Nothing] {
+ def isDefinedAt(x: Any) = false
+ def apply(x: Any) = throw new MatchError(x)
+ override def orElse[A1, B1](that: PartialFunction[A1, B1]) = that
+ override def andThen[C](k: Nothing => C) = this
+ override val lift = (x: Any) => None
+ override def run[U](x: Any)(action: Nothing => U) = false
+ override def runWith[U](action: Nothing => U) = constFalse
+ }
+
+ /**
+ * TODO: comment
+ * @since 2.10
+ */
def empty[A, B] : PartialFunction[A, B] = empty_pf
/** Creates a Boolean test based on a value and a partial function.
@@ -137,8 +207,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: PartialFunction[T, Boolean]): Boolean =
- (pf isDefinedAt x) && pf(x)
+ def cond[T](x: T)(pf: PartialFunction[T, Boolean]): Boolean = pf.applyOrElse(x, constFalse)
/** Transforms a PartialFunction[T, U] `pf` into Function1[T, Option[U]] `f`
* whose result is `Some(x)` if the argument is in `pf`'s domain and `None`
@@ -150,6 +219,5 @@ 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: PartialFunction[T, U]): Option[U] =
- if (pf isDefinedAt x) Some(pf(x)) else None
+ def condOpt[T,U](x: T)(pf: PartialFunction[T, U]): Option[U] = pf.lift(x)
}
diff --git a/src/library/scala/Specializable.scala b/src/library/scala/Specializable.scala
index 67126b3069..d5e22195d2 100644
--- a/src/library/scala/Specializable.scala
+++ b/src/library/scala/Specializable.scala
@@ -20,10 +20,10 @@ object Specializable {
// Smuggle a list of types by way of a tuple upon which Group is parameterized.
class Group[T >: Null](value: T) extends SpecializedGroup { }
- final val Primitives = new Group(Byte, Short, Int, Long, Char, Float, Double, Boolean, Unit)
- final val Everything = new Group(Byte, Short, Int, Long, Char, Float, Double, Boolean, Unit, AnyRef)
- final val Bits32AndUp = new Group(Int, Long, Float, Double)
- final val Integral = new Group(Byte, Short, Int, Long, Char)
- final val AllNumeric = new Group(Byte, Short, Int, Long, Char, Float, Double)
- final val BestOfBreed = new Group(Int, Double, Boolean, Unit, AnyRef)
+ final val Primitives = new Group((Byte, Short, Int, Long, Char, Float, Double, Boolean, Unit))
+ final val Everything = new Group((Byte, Short, Int, Long, Char, Float, Double, Boolean, Unit, AnyRef))
+ final val Bits32AndUp = new Group((Int, Long, Float, Double))
+ final val Integral = new Group((Byte, Short, Int, Long, Char))
+ final val AllNumeric = new Group((Byte, Short, Int, Long, Char, Float, Double))
+ final val BestOfBreed = new Group((Int, Double, Boolean, Unit, AnyRef))
}
diff --git a/src/library/scala/collection/GenIterableLike.scala b/src/library/scala/collection/GenIterableLike.scala
index 7e68733afd..8fa5981969 100644
--- a/src/library/scala/collection/GenIterableLike.scala
+++ b/src/library/scala/collection/GenIterableLike.scala
@@ -40,17 +40,18 @@ trait GenIterableLike[+A, +Repr] extends Any with GenTraversableLike[A, Repr] {
/** Checks if the other iterable collection contains the same elements in the same order as this $coll.
*
- * $orderDependent
- * $willNotTerminateInf
- *
* @param that the collection to compare with.
* @tparam B the type of the elements of collection `that`.
* @return `true`, if both collections contain the same elements in the same order, `false` otherwise.
*
* @usecase def sameElements(that: GenIterable[A]): Boolean
+ * @inheritdoc
*
- * @param that the collection to compare with.
- * @return `true`, if both collections contain the same elements in the same order, `false` otherwise.
+ * $orderDependent
+ * $willNotTerminateInf
+ *
+ * @param that the collection to compare with.
+ * @return `true`, if both collections contain the same elements in the same order, `false` otherwise.
*/
def sameElements[A1 >: A](that: GenIterable[A1]): Boolean
@@ -58,8 +59,6 @@ trait GenIterableLike[+A, +Repr] extends Any with GenTraversableLike[A, Repr] {
* by combining corresponding elements in pairs.
* If one of the two collections is longer than the other, its remaining elements are ignored.
*
- * $orderDependent
- *
* @param that The iterable providing the second half of each result pair
* @tparam A1 the type of the first half of the returned pairs (this is always a supertype
* of the collection's element type `A`).
@@ -71,19 +70,20 @@ trait GenIterableLike[+A, +Repr] extends Any with GenTraversableLike[A, Repr] {
* of the returned collection is the minimum of the lengths of this $coll and `that`.
*
* @usecase def zip[B](that: GenIterable[B]): $Coll[(A, B)]
+ * @inheritdoc
*
- * @param that The iterable providing the second half of each result pair
- * @tparam B the type of the second half of the returned pairs
- * @return a new $coll containing pairs consisting of
- * corresponding elements of this $coll and `that`. The length
- * of the returned collection is the minimum of the lengths of this $coll and `that`.
+ * $orderDependent
+ *
+ * @param that The iterable providing the second half of each result pair
+ * @tparam B the type of the second half of the returned pairs
+ * @return a new $coll containing pairs consisting of
+ * corresponding elements of this $coll and `that`. The length
+ * of the returned collection is the minimum of the lengths of this $coll and `that`.
*/
def zip[A1 >: A, B, That](that: GenIterable[B])(implicit bf: CBF[Repr, (A1, B), That]): That
/** Zips this $coll with its indices.
*
- * $orderDependent
- *
* @tparam A1 the type of the first half of the returned pairs (this is always a supertype
* of the collection's element type `A`).
* @tparam That the class of the returned collection. Where possible, `That` is
@@ -98,11 +98,14 @@ trait GenIterableLike[+A, +Repr] extends Any with GenTraversableLike[A, Repr] {
* $coll paired with their index. Indices start at `0`.
*
* @usecase def zipWithIndex: $Coll[(A, Int)]
+ * @inheritdoc
*
- * @return A new $coll containing pairs consisting of all elements of this
- * $coll paired with their index. Indices start at `0`.
- * @example
- * `List("a", "b", "c").zipWithIndex = List(("a", 0), ("b", 1), ("c", 2))`
+ * $orderDependent
+ *
+ * @return A new $coll containing pairs consisting of all elements of this
+ * $coll paired with their index. Indices start at `0`.
+ * @example
+ * `List("a", "b", "c").zipWithIndex = List(("a", 0), ("b", 1), ("c", 2))`
*
*/
def zipWithIndex[A1 >: A, That](implicit bf: CBF[Repr, (A1, Int), That]): That
@@ -112,8 +115,6 @@ trait GenIterableLike[+A, +Repr] extends Any with GenTraversableLike[A, Repr] {
* If one of the two collections is shorter than the other,
* placeholder elements are used to extend the shorter collection to the length of the longer.
*
- * $orderDependent
- *
* @param that the iterable providing the second half of each result pair
* @param thisElem the element to be used to fill up the result if this $coll is shorter than `that`.
* @param thatElem the element to be used to fill up the result if `that` is shorter than this $coll.
@@ -124,16 +125,19 @@ trait GenIterableLike[+A, +Repr] extends Any with GenTraversableLike[A, Repr] {
* If `that` is shorter than this $coll, `thatElem` values are used to pad the result.
*
* @usecase def zipAll[B](that: Iterable[B], thisElem: A, thatElem: B): $Coll[(A, B)]
- *
- * @param that The iterable providing the second half of each result pair
- * @param thisElem the element to be used to fill up the result if this $coll is shorter than `that`.
- * @param thatElem the element to be used to fill up the result if `that` is shorter than this $coll.
- * @tparam B the type of the second half of the returned pairs
- * @return a new $coll containing pairs consisting of
- * corresponding elements of this $coll and `that`. The length
- * of the returned collection is the maximum of the lengths of this $coll and `that`.
- * If this $coll is shorter than `that`, `thisElem` values are used to pad the result.
- * If `that` is shorter than this $coll, `thatElem` values are used to pad the result.
+ * @inheritdoc
+ *
+ * $orderDependent
+ *
+ * @param that The iterable providing the second half of each result pair
+ * @param thisElem the element to be used to fill up the result if this $coll is shorter than `that`.
+ * @param thatElem the element to be used to fill up the result if `that` is shorter than this $coll.
+ * @tparam B the type of the second half of the returned pairs
+ * @return a new $coll containing pairs consisting of
+ * corresponding elements of this $coll and `that`. The length
+ * of the returned collection is the maximum of the lengths of this $coll and `that`.
+ * If this $coll is shorter than `that`, `thisElem` values are used to pad the result.
+ * If `that` is shorter than this $coll, `thatElem` values are used to pad the result.
*/
def zipAll[B, A1 >: A, That](that: GenIterable[B], thisElem: A1, thatElem: B)(implicit bf: CBF[Repr, (A1, B), That]): That
diff --git a/src/library/scala/collection/GenMapLike.scala b/src/library/scala/collection/GenMapLike.scala
index 12ecbcf140..114169c849 100644
--- a/src/library/scala/collection/GenMapLike.scala
+++ b/src/library/scala/collection/GenMapLike.scala
@@ -41,6 +41,8 @@ trait GenMapLike[A, +B, +Repr] extends GenIterableLike[(A, B), Repr] with Equals
* @return the value associated with `key` if it exists,
* otherwise the result of the `default` computation.
* @usecase def getOrElse(key: A, default: => B): B
+ * @inheritdoc
+ * @tparam B the result type of the default computation.
*/
def getOrElse[B1 >: B](key: A, default: => B1): B1
diff --git a/src/library/scala/collection/GenSeqLike.scala b/src/library/scala/collection/GenSeqLike.scala
index cb0e96fcbb..755abcd2bf 100644
--- a/src/library/scala/collection/GenSeqLike.scala
+++ b/src/library/scala/collection/GenSeqLike.scala
@@ -115,21 +115,21 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal
/** Finds index of first occurrence of some value in this $coll.
*
- * $mayNotTerminateInf
- *
* @param elem the element value to search for.
* @tparam B the type of the element `elem`.
* @return the index of the first element of this $coll that is equal (wrt `==`)
* to `elem`, or `-1`, if none exists.
*
* @usecase def indexOf(elem: A): Int
+ * @inheritdoc
+ *
+ * $mayNotTerminateInf
+ *
*/
def indexOf[B >: A](elem: B): Int = indexOf(elem, 0)
/** Finds index of first occurrence of some value in this $coll after or at some start index.
*
- * $mayNotTerminateInf
- *
* @param elem the element value to search for.
* @tparam B the type of the element `elem`.
* @param from the start index
@@ -137,19 +137,25 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal
* to `elem`, or `-1`, if none exists.
*
* @usecase def indexOf(elem: A, from: Int): Int
+ * @inheritdoc
+ *
+ * $mayNotTerminateInf
+ *
*/
def indexOf[B >: A](elem: B, from: Int): Int = indexWhere(elem ==, from)
/** Finds index of last occurrence of some value in this $coll.
*
- * $willNotTerminateInf
- *
* @param elem the element value to search for.
* @tparam B the type of the element `elem`.
* @return the index of the last element of this $coll that is equal (wrt `==`)
* to `elem`, or `-1`, if none exists.
*
* @usecase def lastIndexOf(elem: A): Int
+ * @inheritdoc
+ *
+ * $willNotTerminateInf
+ *
*/
def lastIndexOf[B >: A](elem: B): Int = lastIndexWhere(elem ==)
@@ -162,6 +168,7 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal
* to `elem`, or `-1`, if none exists.
*
* @usecase def lastIndexOf(elem: A, end: Int): Int
+ * @inheritdoc
*/
def lastIndexOf[B >: A](elem: B, end: Int): Int = lastIndexWhere(elem ==, end)
@@ -195,10 +202,6 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal
* Builds a new collection by applying a function to all elements of this $coll and
* collecting the results in reversed order.
*
- * $willNotTerminateInf
- *
- * Note: `xs.reverseMap(f)` is the same as `xs.reverse.map(f)` but might be more efficient.
- *
* @param f the function to apply to each element.
* @tparam B the element type of the returned collection.
* @tparam That $thatinfo
@@ -207,10 +210,14 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal
* `f` to each element of this $coll and collecting the results in reversed order.
*
* @usecase def reverseMap[B](f: A => B): $Coll[B]
+ * @inheritdoc
*
- * Note: `xs.reverseMap(f)` is the same as `xs.reverse.map(f)` but might be more efficient.
- * @return a new $coll resulting from applying the given function
- * `f` to each element of this $coll and collecting the results in reversed order.
+ * $willNotTerminateInf
+ *
+ * Note: `xs.reverseMap(f)` is the same as `xs.reverse.map(f)` but might be more efficient.
+ *
+ * @return a new $coll resulting from applying the given function
+ * `f` to each element of this $coll and collecting the results in reversed order.
*/
def reverseMap[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That
@@ -254,10 +261,13 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal
* @return a new $coll consisting of all elements of this $coll
* except that `replaced` elements starting from `from` are replaced
* by `patch`.
+ *
* @usecase def patch(from: Int, that: GenSeq[A], replaced: Int): $Coll[A]
- * @return a new $coll consisting of all elements of this $coll
- * except that `replaced` elements starting from `from` are replaced
- * by `patch`.
+ * @inheritdoc
+ *
+ * @return a new $coll consisting of all elements of this $coll
+ * except that `replaced` elements starting from `from` are replaced
+ * by `patch`.
*/
def patch[B >: A, That](from: Int, patch: GenSeq[B], replaced: Int)(implicit bf: CanBuildFrom[Repr, B, That]): That
@@ -268,20 +278,33 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal
* @tparam That $thatinfo
* @param bf $bfinfo
* @return a new $coll` which is a copy of this $coll with the element at position `index` replaced by `elem`.
+ *
* @usecase def updated(index: Int, elem: A): $Coll[A]
- * @return a copy of this $coll with the element at position `index` replaced by `elem`.
+ * @inheritdoc
+ *
+ * @return a copy of this $coll with the element at position `index` replaced by `elem`.
*/
def updated[B >: A, That](index: Int, elem: B)(implicit bf: CanBuildFrom[Repr, B, That]): That
/** A copy of the $coll with an element prepended.
*
- * Note that :-ending operators are right associative (see example).
- * A mnemonic for `+:` vs. `:+` is: the COLon goes on the COLlection side.
+ * @param elem the prepended element
+ * @tparam B the element type of the returned $coll.
+ * @tparam That $thatinfo
+ * @param bf $bfinfo
+ * @return a new collection of type `That` consisting of `elem` followed
+ * by all elements of this $coll.
+ *
+ * @usecase def +:(elem: A): $Coll[A]
+ * @inheritdoc
+ *
+ * Note that :-ending operators are right associative (see example).
+ * A mnemonic for `+:` vs. `:+` is: the COLon goes on the COLlection side.
*
- * Also, the original $coll is not modified, so you will want to capture the result.
+ * Also, the original $coll is not modified, so you will want to capture the result.
*
- * Example:
- * {{{
+ * Example:
+ * {{{
* scala> val x = LinkedList(1)
* x: scala.collection.mutable.LinkedList[Int] = LinkedList(1)
*
@@ -290,17 +313,10 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal
*
* scala> println(x)
* LinkedList(1)
- * }}}
+ * }}}
*
- * @param elem the prepended element
- * @tparam B the element type of the returned $coll.
- * @tparam That $thatinfo
- * @param bf $bfinfo
- * @return a new collection of type `That` consisting of `elem` followed
- * by all elements of this $coll.
- * @usecase def +:(elem: A): $Coll[A]
- * @return a new $coll consisting of `elem` followed
- * by all elements of this $coll.
+ * @return a new $coll consisting of `elem` followed
+ * by all elements of this $coll.
*/
def +:[B >: A, That](elem: B)(implicit bf: CanBuildFrom[Repr, B, That]): That
@@ -308,18 +324,20 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal
*
* A mnemonic for `+:` vs. `:+` is: the COLon goes on the COLlection side.
*
- * $willNotTerminateInf
* @param elem the appended element
* @tparam B the element type of the returned $coll.
* @tparam That $thatinfo
* @param bf $bfinfo
* @return a new collection of type `That` consisting of
* all elements of this $coll followed by `elem`.
+ *
* @usecase def :+(elem: A): $Coll[A]
- * @return a new $coll consisting of
- * all elements of this $coll followed by `elem`.
- * @example
- * {{{
+ * @inheritdoc
+ *
+ * $willNotTerminateInf
+ *
+ * Example:
+ * {{{
* scala> import scala.collection.mutable.LinkedList
* import scala.collection.mutable.LinkedList
*
@@ -331,7 +349,10 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal
*
* scala> println(a)
* LinkedList(1)
- * }}}
+ * }}}
+ *
+ * @return a new $coll consisting of
+ * all elements of this $coll followed by `elem`.
*/
def :+[B >: A, That](elem: B)(implicit bf: CanBuildFrom[Repr, B, That]): That
@@ -346,9 +367,11 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal
* all elements of this $coll followed by the minimal number of occurrences of `elem` so
* that the resulting collection has a length of at least `len`.
* @usecase def padTo(len: Int, elem: A): $Coll[A]
- * @return a new $coll consisting of
- * all elements of this $coll followed by the minimal number of occurrences of `elem` so
- * that the resulting $coll has a length of at least `len`.
+ * @inheritdoc
+ *
+ * @return a new $coll consisting of
+ * all elements of this $coll followed by the minimal number of occurrences of `elem` so
+ * that the resulting $coll has a length of at least `len`.
*/
def padTo[B >: A, That](len: Int, elem: B)(implicit bf: CanBuildFrom[Repr, B, That]): That
@@ -368,13 +391,6 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal
/** Produces a new sequence which contains all elements of this $coll and also all elements of
* a given sequence. `xs union ys` is equivalent to `xs ++ ys`.
- * $willNotTerminateInf
- *
- * Another way to express this
- * is that `xs union ys` computes the order-presevring multi-set union of `xs` and `ys`.
- * `union` is hence a counter-part of `diff` and `intersect` which also work on multi-sets.
- *
- * $willNotTerminateInf
*
* @param that the sequence to add.
* @tparam B the element type of the returned $coll.
@@ -382,9 +398,18 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal
* @param bf $bfinfo
* @return a new collection of type `That` which contains all elements of this $coll
* followed by all elements of `that`.
+ *
* @usecase def union(that: GenSeq[A]): $Coll[A]
- * @return a new $coll which contains all elements of this $coll
- * followed by all elements of `that`.
+ * @inheritdoc
+ *
+ * Another way to express this
+ * is that `xs union ys` computes the order-presevring multi-set union of `xs` and `ys`.
+ * `union` is hence a counter-part of `diff` and `intersect` which also work on multi-sets.
+ *
+ * $willNotTerminateInf
+ *
+ * @return a new $coll which contains all elements of this $coll
+ * followed by all elements of `that`.
*/
def union[B >: A, That](that: GenSeq[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = this ++ that
@@ -393,7 +418,6 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal
union(that: GenSeq[B])(bf)
/** Computes the multiset difference between this $coll and another sequence.
- * $willNotTerminateInf
*
* @param that the sequence of elements to remove
* @tparam B the element type of the returned $coll.
@@ -404,17 +428,21 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal
* If an element value `x` appears
* ''n'' times in `that`, then the first ''n'' occurrences of `x` will not form
* part of the result, but any following occurrences will.
+ *
* @usecase def diff(that: GenSeq[A]): $Coll[A]
- * @return a new $coll which contains all elements of this $coll
- * except some of occurrences of elements that also appear in `that`.
- * If an element value `x` appears
- * ''n'' times in `that`, then the first ''n'' occurrences of `x` will not form
- * part of the result, but any following occurrences will.
+ * @inheritdoc
+ *
+ * $willNotTerminateInf
+ *
+ * @return a new $coll which contains all elements of this $coll
+ * except some of occurrences of elements that also appear in `that`.
+ * If an element value `x` appears
+ * ''n'' times in `that`, then the first ''n'' occurrences of `x` will not form
+ * part of the result, but any following occurrences will.
*/
def diff[B >: A](that: GenSeq[B]): Repr
/** Computes the multiset intersection between this $coll and another sequence.
- * $mayNotTerminateInf
*
* @param that the sequence of elements to intersect with.
* @tparam B the element type of the returned $coll.
@@ -425,12 +453,17 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal
* If an element value `x` appears
* ''n'' times in `that`, then the first ''n'' occurrences of `x` will be retained
* in the result, but any following occurrences will be omitted.
+ *
* @usecase def intersect(that: GenSeq[A]): $Coll[A]
- * @return a new $coll which contains all elements of this $coll
- * which also appear in `that`.
- * If an element value `x` appears
- * ''n'' times in `that`, then the first ''n'' occurrences of `x` will be retained
- * in the result, but any following occurrences will be omitted.
+ * @inheritdoc
+ *
+ * $mayNotTerminateInf
+ *
+ * @return a new $coll which contains all elements of this $coll
+ * which also appear in `that`.
+ * If an element value `x` appears
+ * ''n'' times in `that`, then the first ''n'' occurrences of `x` will be retained
+ * in the result, but any following occurrences will be omitted.
*/
def intersect[B >: A](that: GenSeq[B]): Repr
diff --git a/src/library/scala/collection/GenTraversableLike.scala b/src/library/scala/collection/GenTraversableLike.scala
index dd5f602c41..fd03e0f446 100644
--- a/src/library/scala/collection/GenTraversableLike.scala
+++ b/src/library/scala/collection/GenTraversableLike.scala
@@ -136,6 +136,7 @@ trait GenTraversableLike[+A, +Repr] extends Any with GenTraversableOnce[A] with
* but this is not necessary.
*
* @usecase def foreach(f: A => Unit): Unit
+ * @inheritdoc
*/
def foreach[U](f: A => U): Unit
@@ -149,17 +150,15 @@ trait GenTraversableLike[+A, +Repr] extends Any with GenTraversableOnce[A] with
* `f` to each element of this $coll and collecting the results.
*
* @usecase def map[B](f: A => B): $Coll[B]
- *
- * @return a new $coll resulting from applying the given function
- * `f` to each element of this $coll and collecting the results.
+ * @inheritdoc
+ * @return a new $coll resulting from applying the given function
+ * `f` to each element of this $coll and collecting the results.
*/
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That
/** Builds a new collection by applying a partial function to all elements of this $coll
* on which the function is defined.
*
- * $collectExample
- *
* @param pf the partial function which filters and maps the $coll.
* @tparam B the element type of the returned collection.
* @tparam That $thatinfo
@@ -169,36 +168,18 @@ trait GenTraversableLike[+A, +Repr] extends Any with GenTraversableOnce[A] with
* The order of the elements is preserved.
*
* @usecase def collect[B](pf: PartialFunction[A, B]): $Coll[B]
+ * @inheritdoc
*
- * @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.
+ * $collectExample
+ *
+ * @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 collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That
/** Builds a new collection by applying a function to all elements of this $coll
- * and using the elements of the resulting collections. For example:
- *
- * {{{
- * def getWords(lines: Seq[String]): Seq[String] = lines flatMap (line => line split "\\W+")
- * }}}
- *
- * The type of the resulting collection is guided by the static type of $coll. This might
- * cause unexpected results sometimes. For example:
- *
- * {{{
- * // lettersOf will return a Seq[Char] of likely repeated letters, instead of a Set
- * def lettersOf(words: Seq[String]) = words flatMap (word => word.toSet)
- *
- * // lettersOf will return a Set[Char], not a Seq
- * def lettersOf(words: Seq[String]) = words.toSet flatMap (word => word.toSeq)
- *
- * // xs will be a an Iterable[Int]
- * val xs = Map("a" -> List(11,111), "b" -> List(22,222)).flatMap(_._2)
- *
- * // ys will be a Map[Int, Int]
- * val ys = Map("a" -> List(1 -> 11,1 -> 111), "b" -> List(2 -> 22,2 -> 222)).flatMap(_._2)
- * }}}
+ * and using the elements of the resulting collections.
*
* @param f the function to apply to each element.
* @tparam B the element type of the returned collection.
@@ -208,33 +189,39 @@ trait GenTraversableLike[+A, +Repr] extends Any with GenTraversableOnce[A] with
* `f` to each element of this $coll and concatenating the results.
*
* @usecase def flatMap[B](f: A => GenTraversableOnce[B]): $Coll[B]
+ * @inheritdoc
*
- * @return a new $coll resulting from applying the given collection-valued function
- * `f` to each element of this $coll and concatenating the results.
- */
- def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That
-
- /** Returns a new $coll containing the elements from the left hand operand followed by the elements from the
- * right hand operand. The element type of the $coll is the most specific superclass encompassing
- * the element types of the two operands (see example).
+ * For example:
*
- * Example:
- * {{{
- * scala> val a = LinkedList(1)
- * a: scala.collection.mutable.LinkedList[Int] = LinkedList(1)
+ * {{{
+ * def getWords(lines: Seq[String]): Seq[String] = lines flatMap (line => line split "\\W+")
+ * }}}
*
- * scala> val b = LinkedList(2)
- * b: scala.collection.mutable.LinkedList[Int] = LinkedList(2)
+ * The type of the resulting collection is guided by the static type of $coll. This might
+ * cause unexpected results sometimes. For example:
*
- * scala> val c = a ++ b
- * c: scala.collection.mutable.LinkedList[Int] = LinkedList(1, 2)
+ * {{{
+ * // lettersOf will return a Seq[Char] of likely repeated letters, instead of a Set
+ * def lettersOf(words: Seq[String]) = words flatMap (word => word.toSet)
*
- * scala> val d = LinkedList('a')
- * d: scala.collection.mutable.LinkedList[Char] = LinkedList(a)
+ * // lettersOf will return a Set[Char], not a Seq
+ * def lettersOf(words: Seq[String]) = words.toSet flatMap (word => word.toSeq)
*
- * scala> val e = c ++ d
- * e: scala.collection.mutable.LinkedList[AnyVal] = LinkedList(1, 2, a)
- * }}}
+ * // xs will be a an Iterable[Int]
+ * val xs = Map("a" -> List(11,111), "b" -> List(22,222)).flatMap(_._2)
+ *
+ * // ys will be a Map[Int, Int]
+ * val ys = Map("a" -> List(1 -> 11,1 -> 111), "b" -> List(2 -> 22,2 -> 222)).flatMap(_._2)
+ * }}}
+ *
+ * @return a new $coll resulting from applying the given collection-valued function
+ * `f` to each element of this $coll and concatenating the results.
+ */
+ def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That
+
+ /** Returns a new $coll containing the elements from the left hand operand followed by the elements from the
+ * right hand operand. The element type of the $coll is the most specific superclass encompassing
+ * the element types of the two operands.
*
* @param that the traversable to append.
* @tparam B the element type of the returned collection.
@@ -244,9 +231,28 @@ trait GenTraversableLike[+A, +Repr] extends Any with GenTraversableOnce[A] with
* of this $coll followed by all elements of `that`.
*
* @usecase def ++[B](that: GenTraversableOnce[B]): $Coll[B]
+ * @inheritdoc
+ *
+ * Example:
+ * {{{
+ * scala> val a = LinkedList(1)
+ * a: scala.collection.mutable.LinkedList[Int] = LinkedList(1)
+ *
+ * scala> val b = LinkedList(2)
+ * b: scala.collection.mutable.LinkedList[Int] = LinkedList(2)
+ *
+ * scala> val c = a ++ b
+ * c: scala.collection.mutable.LinkedList[Int] = LinkedList(1, 2)
+ *
+ * scala> val d = LinkedList('a')
+ * d: scala.collection.mutable.LinkedList[Char] = LinkedList(a)
+ *
+ * scala> val e = c ++ d
+ * e: scala.collection.mutable.LinkedList[AnyVal] = LinkedList(1, 2, a)
+ * }}}
*
- * @return a new $coll which contains all elements of this $coll
- * followed by all elements of `that`.
+ * @return a new $coll which contains all elements of this $coll
+ * followed by all elements of `that`.
*/
def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That
diff --git a/src/library/scala/collection/GenTraversableOnce.scala b/src/library/scala/collection/GenTraversableOnce.scala
index 67ea4cdb00..a7ec7618b7 100644
--- a/src/library/scala/collection/GenTraversableOnce.scala
+++ b/src/library/scala/collection/GenTraversableOnce.scala
@@ -124,7 +124,7 @@ trait GenTraversableOnce[+A] extends Any {
* scala> val b = (a /:\ 5)(_+_)
* b: Int = 15
* }}}*/
- @deprecated("use fold instead")
+ @deprecated("use fold instead", "2.10.0")
def /:\[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 = fold(z)(op)
/** Applies a binary operator to a start value and all elements of this $coll,
@@ -156,7 +156,7 @@ trait GenTraversableOnce[+A] extends Any {
* @return the result of inserting `op` between consecutive elements of this $coll,
* going left to right with the start value `z` on the left:
* {{{
- * op(...op(op(z, x1), x2), ..., xn)
+ * op(...op(op(z, x_1), x_2), ..., x_n)
* }}}
* where `x,,1,,, ..., x,,n,,` are the elements of this $coll.
*/
@@ -191,7 +191,7 @@ trait GenTraversableOnce[+A] extends Any {
* @return the result of inserting `op` between consecutive elements of this $coll,
* going right to left with the start value `z` on the right:
* {{{
- * op(x1, op(x2, ... op(xn, z)...))
+ * op(x_1, op(x_2, ... op(x_n, z)...))
* }}}
* where `x,,1,,, ..., x,,n,,` are the elements of this $coll.
*/
@@ -209,7 +209,7 @@ trait GenTraversableOnce[+A] extends Any {
* @return the result of inserting `op` between consecutive elements of this $coll,
* going left to right with the start value `z` on the left:
* {{{
- * op(...op(z, x1), x2, ..., xn)
+ * op(...op(z, x_1), x_2, ..., x_n)
* }}}
* where `x,,1,,, ..., x,,n,,` are the elements of this $coll.
*/
@@ -226,7 +226,7 @@ trait GenTraversableOnce[+A] extends Any {
* @return the result of inserting `op` between consecutive elements of this $coll,
* going right to left with the start value `z` on the right:
* {{{
- * op(x1, op(x2, ... op(xn, z)...))
+ * op(x_1, op(x_2, ... op(x_n, z)...))
* }}}
* where `x,,1,,, ..., x,,n,,` are the elements of this $coll.
*/
@@ -271,7 +271,7 @@ trait GenTraversableOnce[+A] extends Any {
* @return the result of inserting `op` between consecutive elements of this $coll,
* going right to left:
* {{{
- * op(x,,1,,, op(x,,2,,, ..., op(x,,n-1,,, x,,n,,)...))
+ * op(x_1, op(x_2, ..., op(x_{n-1}, x_n)...))
* }}}
* where `x,,1,,, ..., x,,n,,` are the elements of this $coll.
* @throws `UnsupportedOperationException` if this $coll is empty.
@@ -316,11 +316,12 @@ trait GenTraversableOnce[+A] extends Any {
* @return the sum of all elements of this $coll with respect to the `+` operator in `num`.
*
* @usecase def sum: A
+ * @inheritdoc
*
- * @return the sum of all elements in this $coll of numbers of type `Int`.
- * Instead of `Int`, any other type `T` with an implicit `Numeric[T]` implementation
- * can be used as element type of the $coll and as result type of `sum`.
- * Examples of such types are: `Long`, `Float`, `Double`, `BigInt`.
+ * @return the sum of all elements in this $coll of numbers of type `Int`.
+ * Instead of `Int`, any other type `T` with an implicit `Numeric[T]` implementation
+ * can be used as element type of the $coll and as result type of `sum`.
+ * Examples of such types are: `Long`, `Float`, `Double`, `BigInt`.
*
*/
def sum[A1 >: A](implicit num: Numeric[A1]): A1
@@ -333,11 +334,12 @@ trait GenTraversableOnce[+A] extends Any {
* @return the product of all elements of this $coll with respect to the `*` operator in `num`.
*
* @usecase def product: A
+ * @inheritdoc
*
- * @return the product of all elements in this $coll of numbers of type `Int`.
- * Instead of `Int`, any other type `T` with an implicit `Numeric[T]` implementation
- * can be used as element type of the $coll and as result type of `product`.
- * Examples of such types are: `Long`, `Float`, `Double`, `BigInt`.
+ * @return the product of all elements in this $coll of numbers of type `Int`.
+ * Instead of `Int`, any other type `T` with an implicit `Numeric[T]` implementation
+ * can be used as element type of the $coll and as result type of `product`.
+ * Examples of such types are: `Long`, `Float`, `Double`, `BigInt`.
*/
def product[A1 >: A](implicit num: Numeric[A1]): A1
@@ -348,7 +350,9 @@ trait GenTraversableOnce[+A] extends Any {
* @return the smallest element of this $coll with respect to the ordering `cmp`.
*
* @usecase def min: A
- * @return the smallest element of this $coll
+ * @inheritdoc
+ *
+ * @return the smallest element of this $coll
*/
def min[A1 >: A](implicit ord: Ordering[A1]): A
@@ -359,7 +363,9 @@ trait GenTraversableOnce[+A] extends Any {
* @return the largest element of this $coll with respect to the ordering `cmp`.
*
* @usecase def max: A
- * @return the largest element of this $coll.
+ * @inheritdoc
+ *
+ * @return the largest element of this $coll.
*/
def max[A1 >: A](implicit ord: Ordering[A1]): A
@@ -387,12 +393,13 @@ trait GenTraversableOnce[+A] extends Any {
* Copying will stop once either the end of the current $coll is reached,
* or the end of the array is reached.
*
- * $willNotTerminateInf
- *
* @param xs the array to fill.
* @tparam B the type of the elements of the array.
*
* @usecase def copyToArray(xs: Array[A]): Unit
+ * @inheritdoc
+ *
+ * $willNotTerminateInf
*/
def copyToArray[B >: A](xs: Array[B]): Unit
@@ -401,13 +408,14 @@ trait GenTraversableOnce[+A] extends Any {
* Copying will stop once either the end of the current $coll is reached,
* or the end of the array is reached.
*
- * $willNotTerminateInf
- *
* @param xs the array to fill.
* @param start the starting index.
* @tparam B the type of the elements of the array.
*
* @usecase def copyToArray(xs: Array[A], start: Int): Unit
+ * @inheritdoc
+ *
+ * $willNotTerminateInf
*/
def copyToArray[B >: A](xs: Array[B], start: Int): Unit
@@ -450,15 +458,18 @@ trait GenTraversableOnce[+A] extends Any {
def mkString: String
/** Converts this $coll to an array.
- * $willNotTerminateInf
*
* @tparam B the type of the elements of the array. A `ClassManifest` for
* this type must be available.
* @return an array containing all elements of this $coll.
*
* @usecase def toArray: Array[A]
- * @return an array containing all elements of this $coll.
- * A `ClassManifest` must be available for the element type of this $coll.
+ * @inheritdoc
+ *
+ * $willNotTerminateInf
+ *
+ * @return an array containing all elements of this $coll.
+ * A `ClassManifest` must be available for the element type of this $coll.
*/
def toArray[A1 >: A: ClassManifest]: Array[A1]
@@ -530,11 +541,13 @@ trait GenTraversableOnce[+A] extends Any {
* 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.
+ *
* @usecase def toMap[T, U]: Map[T, U]
- * @return a map of type `immutable.Map[T, U]`
- * containing all key/value pairs of type `(T, U)` of this $coll.
+ * @inheritdoc
+ * $willNotTerminateInf
+ * @return a map of type `immutable.Map[T, U]`
+ * containing all key/value pairs of type `(T, U)` of this $coll.
*/
def toMap[K, V](implicit ev: A <:< (K, V)): GenMap[K, V]
}
diff --git a/src/library/scala/collection/IterableLike.scala b/src/library/scala/collection/IterableLike.scala
index 73d4efe125..fb6d154952 100644
--- a/src/library/scala/collection/IterableLike.scala
+++ b/src/library/scala/collection/IterableLike.scala
@@ -67,6 +67,7 @@ self =>
* Subclasses should re-implement this method if a more efficient implementation exists.
*
* @usecase def foreach(f: A => Unit): Unit
+ * @inheritdoc
*/
def foreach[U](f: A => U): Unit =
iterator.foreach(f)
diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala
index d46d215e0c..7b57a91c41 100644
--- a/src/library/scala/collection/Iterator.scala
+++ b/src/library/scala/collection/Iterator.scala
@@ -322,7 +322,9 @@ trait Iterator[+A] extends TraversableOnce[A] {
* @return a new iterator that first yields the values produced by this
* iterator followed by the values produced by iterator `that`.
* @note Reuse: $consumesTwoAndProducesOneIterator
+ *
* @usecase def ++(that: => Iterator[A]): Iterator[A]
+ * @inheritdoc
*/
def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] = new AbstractIterator[B] {
// optimize a little bit to prevent n log n behavior.
@@ -609,7 +611,9 @@ trait Iterator[+A] extends TraversableOnce[A] {
* followed by the minimal number of occurrences of `elem` so
* that the number of produced values is at least `len`.
* @note Reuse: $consumesAndProducesIterator
+ *
* @usecase def padTo(len: Int, elem: A): Iterator[A]
+ * @inheritdoc
*/
def padTo[A1 >: A](len: Int, elem: A1): Iterator[A1] = new AbstractIterator[A1] {
private var count = 0
@@ -658,7 +662,9 @@ trait Iterator[+A] extends TraversableOnce[A] {
* If this iterator is shorter than `that`, `thisElem` values are used to pad the result.
* If `that` is shorter than this iterator, `thatElem` values are used to pad the result.
* @note Reuse: $consumesTwoAndProducesOneIterator
+ *
* @usecase def zipAll[B](that: Iterator[B], thisElem: A, thatElem: B): Iterator[(A, B)]
+ * @inheritdoc
*/
def zipAll[B, A1 >: A, B1 >: B](that: Iterator[B], thisElem: A1, thatElem: B1): Iterator[(A1, B1)] = new AbstractIterator[(A1, B1)] {
def hasNext = self.hasNext || that.hasNext
@@ -682,7 +688,9 @@ trait Iterator[+A] extends TraversableOnce[A] {
* but this is not necessary.
*
* @note Reuse: $consumesIterator
+ *
* @usecase def foreach(f: A => Unit): Unit
+ * @inheritdoc
*/
def foreach[U](f: A => U) { while (hasNext) f(next()) }
@@ -1057,15 +1065,17 @@ trait Iterator[+A] extends TraversableOnce[A] {
* Copying will stop once either the end of the current iterator is reached,
* or the end of the array is reached, or `len` elements have been copied.
*
- * $willNotTerminateInf
- *
* @param xs the array to fill.
* @param start the starting index.
* @param len the maximal number of elements to copy.
* @tparam B the type of the elements of the array.
*
* @note Reuse: $consumesIterator
+ *
* @usecase def copyToArray(xs: Array[A], start: Int, len: Int): Unit
+ * @inheritdoc
+ *
+ * $willNotTerminateInf
*/
def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Unit = {
var i = start
diff --git a/src/library/scala/collection/JavaConversions.scala b/src/library/scala/collection/JavaConversions.scala
index 03f1fe07ab..a978a9a783 100644
--- a/src/library/scala/collection/JavaConversions.scala
+++ b/src/library/scala/collection/JavaConversions.scala
@@ -8,6 +8,9 @@
package scala.collection
+import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc }
+import convert._
+
/** A collection of implicit conversions supporting interoperability between
* Scala and Java collections.
*
@@ -46,941 +49,83 @@ package scala.collection
* @author Martin Odersky
* @since 2.8
*/
-object JavaConversions {
+object JavaConversions extends WrapAsScala with WrapAsJava {
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type ConcurrentMapWrapper[A, B] = Wrappers.ConcurrentMapWrapper[A, B]
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type DictionaryWrapper[A, B] = Wrappers.DictionaryWrapper[A, B]
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type IterableWrapper[A] = Wrappers.IterableWrapper[A]
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type IteratorWrapper[A] = Wrappers.IteratorWrapper[A]
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type JCollectionWrapper[A] = Wrappers.JCollectionWrapper[A]
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type JConcurrentMapWrapper[A, B] = Wrappers.JConcurrentMapWrapper[A, B]
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type JDictionaryWrapper[A, B] = Wrappers.JDictionaryWrapper[A, B]
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type JEnumerationWrapper[A] = Wrappers.JEnumerationWrapper[A]
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type JIterableWrapper[A] = Wrappers.JIterableWrapper[A]
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type JIteratorWrapper[A] = Wrappers.JIteratorWrapper[A]
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type JListWrapper[A] = Wrappers.JListWrapper[A]
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type JMapWrapper[A, B] = Wrappers.JMapWrapper[A, B]
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type JPropertiesWrapper = Wrappers.JPropertiesWrapper
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type JSetWrapper[A] = Wrappers.JSetWrapper[A]
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type MapWrapper[A, B] = Wrappers.MapWrapper[A, B]
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type MutableBufferWrapper[A] = Wrappers.MutableBufferWrapper[A]
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type MutableMapWrapper[A, B] = Wrappers.MutableMapWrapper[A, B]
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type MutableSeqWrapper[A] = Wrappers.MutableSeqWrapper[A]
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type MutableSetWrapper[A] = Wrappers.MutableSetWrapper[A]
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type SeqWrapper[A] = Wrappers.SeqWrapper[A]
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type SetWrapper[A] = Wrappers.SetWrapper[A]
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") type ToIteratorWrapper[A] = Wrappers.ToIteratorWrapper[A]
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") val DictionaryWrapper = Wrappers.DictionaryWrapper
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") val IterableWrapper = Wrappers.IterableWrapper
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") val IteratorWrapper = Wrappers.IteratorWrapper
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") val JCollectionWrapper = Wrappers.JCollectionWrapper
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") val JConcurrentMapWrapper = Wrappers.JConcurrentMapWrapper
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") val JDictionaryWrapper = Wrappers.JDictionaryWrapper
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") val JEnumerationWrapper = Wrappers.JEnumerationWrapper
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") val JIterableWrapper = Wrappers.JIterableWrapper
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") val JIteratorWrapper = Wrappers.JIteratorWrapper
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") val JListWrapper = Wrappers.JListWrapper
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") val JMapWrapper = Wrappers.JMapWrapper
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") val JPropertiesWrapper = Wrappers.JPropertiesWrapper
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") val JSetWrapper = Wrappers.JSetWrapper
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") val MutableBufferWrapper = Wrappers.MutableBufferWrapper
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") val MutableMapWrapper = Wrappers.MutableMapWrapper
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") val MutableSeqWrapper = Wrappers.MutableSeqWrapper
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") val MutableSetWrapper = Wrappers.MutableSetWrapper
+ @deprecated("Use a member of scala.collection.convert.Wrappers", "2.10.0") val SeqWrapper = Wrappers.SeqWrapper
+
// Note to implementors: the cavalcade of deprecated methods herein should
// serve as a warning to any who follow: don't overload implicit methods.
- import java.{ lang => jl, util => ju }
- import java.util.{ concurrent => juc }
-
- // Scala => Java
-
- /**
- * Implicitly converts a Scala Iterator to a Java Iterator.
- * The returned Java Iterator is backed by the provided Scala
- * Iterator and any side-effects of using it via the Java interface will
- * be visible via the Scala interface and vice versa.
- *
- * If the Scala Iterator was previously obtained from an implicit or
- * explicit call of `asIterator(java.util.Iterator)` then the original
- * Java Iterator will be returned.
- *
- * @param i The Iterator to be converted.
- * @return A Java Iterator view of the argument.
- */
- implicit def asJavaIterator[A](it: Iterator[A]): ju.Iterator[A] = it match {
- case JIteratorWrapper(wrapped) => wrapped.asInstanceOf[ju.Iterator[A]]
- case _ => IteratorWrapper(it)
- }
-
- /**
- * Implicitly converts a Scala Iterator to a Java Enumeration.
- * The returned Java Enumeration is backed by the provided Scala
- * Iterator and any side-effects of using it via the Java interface will
- * be visible via the Scala interface and vice versa.
- *
- * If the Scala Iterator was previously obtained from an implicit or
- * explicit call of `asIterator(java.util.Enumeration)` then the
- * original Java Enumeration will be returned.
- *
- * @param i The Iterator to be converted.
- * @return A Java Enumeration view of the argument.
- */
- implicit def asJavaEnumeration[A](it: Iterator[A]): ju.Enumeration[A] = it match {
- case JEnumerationWrapper(wrapped) => wrapped.asInstanceOf[ju.Enumeration[A]]
- case _ => IteratorWrapper(it)
- }
-
- /**
- * Implicitly converts a Scala Iterable to a Java Iterable.
- * The returned Java Iterable is backed by the provided Scala
- * Iterable and any side-effects of using it via the Java interface will
- * be visible via the Scala interface and vice versa.
- *
- * If the Scala Iterable was previously obtained from an implicit or
- * explicit call of `asIterable(java.lang.Iterable)` then the original
- * Java Iterable will be returned.
- *
- * @param i The Iterable to be converted.
- * @return A Java Iterable view of the argument.
- */
- implicit def asJavaIterable[A](i: Iterable[A]): jl.Iterable[A] = i match {
- case JIterableWrapper(wrapped) => wrapped.asInstanceOf[jl.Iterable[A]]
- case _ => IterableWrapper(i)
- }
-
- /**
- * Implicitly converts a Scala Iterable to an immutable Java
- * Collection.
- *
- * If the Scala Iterable was previously obtained from an implicit or
- * explicit call of `asSizedIterable(java.util.Collection)` then the original
- * Java Collection will be returned.
- *
- * @param i The SizedIterable to be converted.
- * @return A Java Collection view of the argument.
- */
- implicit def asJavaCollection[A](it: Iterable[A]): ju.Collection[A] = it match {
- case JCollectionWrapper(wrapped) => wrapped.asInstanceOf[ju.Collection[A]]
- case _ => new IterableWrapper(it)
- }
-
- /**
- * Implicitly converts a Scala mutable Buffer to a Java List.
- * The returned Java List is backed by the provided Scala
- * Buffer and any side-effects of using it via the Java interface will
- * be visible via the Scala interface and vice versa.
- *
- * If the Scala Buffer was previously obtained from an implicit or
- * explicit call of `asBuffer(java.util.List)` then the original
- * Java List will be returned.
- *
- * @param b The Buffer to be converted.
- * @return A Java List view of the argument.
- */
- implicit def bufferAsJavaList[A](b: mutable.Buffer[A]): ju.List[A] = b match {
- case JListWrapper(wrapped) => wrapped
- case _ => new MutableBufferWrapper(b)
- }
@deprecated("use bufferAsJavaList instead", "2.9.0")
def asJavaList[A](b : mutable.Buffer[A]): ju.List[A] = bufferAsJavaList[A](b)
- /**
- * Implicitly converts a Scala mutable Seq to a Java List.
- * The returned Java List is backed by the provided Scala
- * Seq and any side-effects of using it via the Java interface will
- * be visible via the Scala interface and vice versa.
- *
- * If the Scala Seq was previously obtained from an implicit or
- * explicit call of `asSeq(java.util.List)` then the original
- * Java List will be returned.
- *
- * @param b The Seq to be converted.
- * @return A Java List view of the argument.
- */
- implicit def mutableSeqAsJavaList[A](seq: mutable.Seq[A]): ju.List[A] = seq match {
- case JListWrapper(wrapped) => wrapped
- case _ => new MutableSeqWrapper(seq)
- }
@deprecated("use mutableSeqAsJavaList instead", "2.9.0")
def asJavaList[A](b : mutable.Seq[A]): ju.List[A] = mutableSeqAsJavaList[A](b)
- /**
- * Implicitly converts a Scala Seq to a Java List.
- * The returned Java List is backed by the provided Scala
- * Seq and any side-effects of using it via the Java interface will
- * be visible via the Scala interface and vice versa.
- *
- * If the Scala Seq was previously obtained from an implicit or
- * explicit call of `asSeq(java.util.List)` then the original
- * Java List will be returned.
- *
- * @param b The Seq to be converted.
- * @return A Java List view of the argument.
- */
- implicit def seqAsJavaList[A](seq: Seq[A]): ju.List[A] = seq match {
- case JListWrapper(wrapped) => wrapped.asInstanceOf[ju.List[A]]
- case _ => new SeqWrapper(seq)
- }
-
@deprecated("use seqAsJavaList instead", "2.9.0")
def asJavaList[A](b : Seq[A]): ju.List[A] = seqAsJavaList[A](b)
- /**
- * Implicitly converts a Scala mutable Set to a Java Set.
- * The returned Java Set is backed by the provided Scala
- * Set and any side-effects of using it via the Java interface will
- * be visible via the Scala interface and vice versa.
- *
- * If the Scala Set was previously obtained from an implicit or
- * explicit call of `asSet(java.util.Set)` then the original
- * Java Set will be returned.
- *
- * @param s The Set to be converted.
- * @return A Java Set view of the argument.
- */
- implicit def mutableSetAsJavaSet[A](s: mutable.Set[A]): ju.Set[A] = s match {
- case JSetWrapper(wrapped) => wrapped
- case _ => new MutableSetWrapper(s)
- }
-
@deprecated("use mutableSetAsJavaSet instead", "2.9.0")
def asJavaSet[A](s : mutable.Set[A]): ju.Set[A] = mutableSetAsJavaSet[A](s)
- /**
- * Implicitly converts a Scala Set to a Java Set.
- * The returned Java Set is backed by the provided Scala
- * Set and any side-effects of using it via the Java interface will
- * be visible via the Scala interface and vice versa.
- *
- * If the Scala Set was previously obtained from an implicit or
- * explicit call of asSet(java.util.Set) then the original
- * Java Set will be returned.
- *
- * @param s The Set to be converted.
- * @return A Java Set view of the argument.
- */
- implicit def setAsJavaSet[A](s: Set[A]): ju.Set[A] = s match {
- case JSetWrapper(wrapped) => wrapped
- case _ => new SetWrapper(s)
- }
-
@deprecated("use setAsJavaSet instead", "2.9.0")
def asJavaSet[A](s: Set[A]): ju.Set[A] = setAsJavaSet[A](s)
- /**
- * Implicitly converts a Scala mutable Map to a Java Map.
- * The returned Java Map is backed by the provided Scala
- * Map and any side-effects of using it via the Java interface will
- * be visible via the Scala interface and vice versa.
- *
- * If the Scala Map was previously obtained from an implicit or
- * explicit call of `asMap(java.util.Map)` then the original
- * Java Map will be returned.
- *
- * @param m The Map to be converted.
- * @return A Java Map view of the argument.
- */
- implicit def mutableMapAsJavaMap[A, B](m: mutable.Map[A, B]): ju.Map[A, B] = m match {
- //case JConcurrentMapWrapper(wrapped) => wrapped
- case JMapWrapper(wrapped) => wrapped
- case _ => new MutableMapWrapper(m)
- }
-
@deprecated("use mutableMapAsJavaMap instead", "2.9.0")
def asJavaMap[A, B](m : mutable.Map[A, B]): ju.Map[A, B] = mutableMapAsJavaMap[A, B](m)
- /**
- * Implicitly converts a Scala mutable `Map` to a Java `Dictionary`.
- *
- * The returned Java `Dictionary` is backed by the provided Scala
- * `Dictionary` and any side-effects of using it via the Java interface
- * will be visible via the Scala interface and vice versa.
- *
- * If the Scala `Dictionary` was previously obtained from an implicit or
- * explicit call of `asMap(java.util.Dictionary)` then the original
- * Java Dictionary will be returned.
- *
- * @param m The `Map` to be converted.
- * @return A Java `Dictionary` view of the argument.
- */
- implicit def asJavaDictionary[A, B](m: mutable.Map[A, B]): ju.Dictionary[A, B] = m match {
- //case JConcurrentMapWrapper(wrapped) => wrapped
- case JDictionaryWrapper(wrapped) => wrapped
- case _ => new DictionaryWrapper(m)
- }
-
- /**
- * Implicitly converts a Scala `Map` to a Java `Map`.
- *
- * The returned Java `Map` is backed by the provided Scala `Map` and
- * any side-effects of using it via the Java interface will be visible
- * via the Scala interface and vice versa.
- *
- * If the Scala `Map` was previously obtained from an implicit or
- * explicit call of `asMap(java.util.Map)` then the original
- * Java `Map` will be returned.
- *
- * @param m The `Map` to be converted.
- * @return A Java `Map` view of the argument.
- */
- implicit def mapAsJavaMap[A, B](m: Map[A, B]): ju.Map[A, B] = m match {
- //case JConcurrentMapWrapper(wrapped) => wrapped
- case JMapWrapper(wrapped) => wrapped.asInstanceOf[ju.Map[A, B]]
- case _ => new MapWrapper(m)
- }
-
@deprecated("use mapAsJavaMap instead", "2.9.0")
def asJavaMap[A, B](m : Map[A, B]): ju.Map[A, B] = mapAsJavaMap[A, B](m)
- @deprecated("Use `concurrent.Map` instead of `mutable.ConcurrentMap`", "2.10.0")
- def asJavaConcurrentMap[A, B](m: mutable.ConcurrentMap[A, B]): juc.ConcurrentMap[A, B] = m match {
- case JConcurrentMapWrapper(wrapped) => wrapped
- case _ => new ConcurrentMapWrapper(m)
- }
-
- /**
- * Implicitly converts a Scala mutable `concurrent.Map` to a Java
- * `ConcurrentMap`.
- *
- * The returned Java `ConcurrentMap` is backed by the provided Scala
- * `concurrent.Map` and any side-effects of using it via the Java interface
- * will be visible via the Scala interface and vice versa.
- *
- * If the Scala `concurrent.Map` was previously obtained from an implicit or
- * explicit call of `javaConcurrentMapAsScalaConcurrentMap(java.util.concurrect.ConcurrentMap)`
- * then the original Java ConcurrentMap will be returned.
- *
- * @param m The `concurrent.Map` to be converted.
- * @return A Java `ConcurrentMap` view of the argument.
- */
- implicit def asJavaConcurrentMap[A, B](m: concurrent.Map[A, B]): juc.ConcurrentMap[A, B] = m match {
- case JavaConcurrentMapWrapper(wrapped) => wrapped
- case _ => new ScalaConcurrentMapWrapper(m)
- }
-
- // Java => Scala
-
- /**
- * Implicitly converts a Java `Iterator` to a Scala `Iterator`.
- *
- * The returned Scala `Iterator` is backed by the provided Java `Iterator`
- * and any side-effects of using it via the Scala interface will be visible
- * via the Java interface and vice versa.
- *
- * If the Java `Iterator` was previously obtained from an implicit or
- * explicit call of `asIterator(scala.collection.Iterator)` then the
- * original Scala `Iterator` will be returned.
- *
- * @param i The `Iterator` to be converted.
- * @return A Scala `Iterator` view of the argument.
- */
- implicit def asScalaIterator[A](it: ju.Iterator[A]): Iterator[A] = it match {
- case IteratorWrapper(wrapped) => wrapped
- case _ => JIteratorWrapper(it)
- }
-
- /**
- * Implicitly converts a Java Enumeration to a Scala Iterator.
- * The returned Scala Iterator is backed by the provided Java
- * Enumeration and any side-effects of using it via the Scala interface will
- * be visible via the Java interface and vice versa.
- *
- * If the Java Enumeration was previously obtained from an implicit or
- * explicit call of `enumerationAsScalaIterator(scala.collection.Iterator)`
- * then the original Scala Iterator will be returned.
- *
- * @param i The Enumeration to be converted.
- * @return A Scala Iterator view of the argument.
- */
- implicit def enumerationAsScalaIterator[A](i: ju.Enumeration[A]): Iterator[A] = i match {
- case IteratorWrapper(wrapped) => wrapped
- case _ => JEnumerationWrapper(i)
- }
-
- /**
- * Implicitly converts a Java `Iterable` to a Scala `Iterable`.
- *
- * The returned Scala `Iterable` is backed by the provided Java `Iterable`
- * and any side-effects of using it via the Scala interface will be visible
- * via the Java interface and vice versa.
- *
- * If the Java `Iterable` was previously obtained from an implicit or
- * explicit call of `iterableAsScalaIterable(scala.collection.Iterable)`
- * then the original Scala Iterable will be returned.
- *
- * @param i The Iterable to be converted.
- * @return A Scala Iterable view of the argument.
- */
- implicit def iterableAsScalaIterable[A](i: jl.Iterable[A]): Iterable[A] = i match {
- case IterableWrapper(wrapped) => wrapped
- case _ => JIterableWrapper(i)
- }
-
@deprecated("use iterableAsScalaIterable instead", "2.9.0")
def asScalaIterable[A](i : jl.Iterable[A]): Iterable[A] = iterableAsScalaIterable[A](i)
- /**
- * Implicitly converts a Java `Collection` to an Scala `Iterable`.
- *
- * If the Java `Collection` was previously obtained from an implicit or
- * explicit call of `collectionAsScalaIterable(scala.collection.SizedIterable)`
- * then the original Scala `Iterable` will be returned.
- *
- * @param i The Collection to be converted.
- * @return A Scala Iterable view of the argument.
- */
- implicit def collectionAsScalaIterable[A](i: ju.Collection[A]): Iterable[A] = i match {
- case IterableWrapper(wrapped) => wrapped
- case _ => JCollectionWrapper(i)
- }
@deprecated("use collectionAsScalaIterable instead", "2.9.0")
def asScalaIterable[A](i : ju.Collection[A]): Iterable[A] = collectionAsScalaIterable[A](i)
- /**
- * Implicitly converts a Java `List` to a Scala mutable `Buffer`.
- *
- * The returned Scala `Buffer` is backed by the provided Java `List`
- * and any side-effects of using it via the Scala interface will
- * be visible via the Java interface and vice versa.
- *
- * If the Java `List` was previously obtained from an implicit or
- * explicit call of `asScalaBuffer(scala.collection.mutable.Buffer)`
- * then the original Scala `Buffer` will be returned.
- *
- * @param l The `List` to be converted.
- * @return A Scala mutable `Buffer` view of the argument.
- */
- implicit def asScalaBuffer[A](l: ju.List[A]): mutable.Buffer[A] = l match {
- case MutableBufferWrapper(wrapped) => wrapped
- case _ =>new JListWrapper(l)
- }
-
- /**
- * Implicitly converts a Java Set to a Scala mutable Set.
- * The returned Scala Set is backed by the provided Java
- * Set and any side-effects of using it via the Scala interface will
- * be visible via the Java interface and vice versa.
- *
- * If the Java Set was previously obtained from an implicit or
- * explicit call of `asScalaSet(scala.collection.mutable.Set)` then
- * the original Scala Set will be returned.
- *
- * @param s The Set to be converted.
- * @return A Scala mutable Set view of the argument.
- */
- implicit def asScalaSet[A](s: ju.Set[A]): mutable.Set[A] = s match {
- case MutableSetWrapper(wrapped) => wrapped
- case _ =>new JSetWrapper(s)
- }
-
- /**
- * Implicitly converts a Java `Map` to a Scala mutable `Map`.
- *
- * The returned Scala `Map` is backed by the provided Java `Map` and any
- * side-effects of using it via the Scala interface will be visible via
- * the Java interface and vice versa.
- *
- * If the Java `Map` was previously obtained from an implicit or
- * explicit call of `mapAsScalaMap(scala.collection.mutable.Map)` then
- * the original Scala Map will be returned.
- *
- * @param m The Map to be converted.
- * @return A Scala mutable Map view of the argument.
- */
- implicit def mapAsScalaMap[A, B](m: ju.Map[A, B]): mutable.Map[A, B] = m match {
- //case ConcurrentMapWrapper(wrapped) => wrapped
- case MutableMapWrapper(wrapped) => wrapped
- case _ => new JMapWrapper(m)
- }
-
@deprecated("use mapAsScalaMap instead", "2.9.0")
def asScalaMap[A, B](m: ju.Map[A, B]): mutable.Map[A, B] = mapAsScalaMap[A, B](m)
- @deprecated("Use `javaConcurrentMapAsScalaConcurrentMap` instead.", "2.10.0")
- def asScalaConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): mutable.ConcurrentMap[A, B] = m match {
- case cmw: ConcurrentMapWrapper[a, b] => cmw.underlying
- case _ => new JConcurrentMapWrapper(m)
- }
-
- /**
- * Implicitly converts a Java ConcurrentMap to a Scala mutable ConcurrentMap.
- * The returned Scala ConcurrentMap is backed by the provided Java
- * ConcurrentMap and any side-effects of using it via the Scala interface will
- * be visible via the Java interface and vice versa.
- *
- * If the Java ConcurrentMap was previously obtained from an implicit or
- * explicit call of `asConcurrentMap(scala.collection.mutable.ConcurrentMap)`
- * then the original Scala ConcurrentMap will be returned.
- *
- * @param m The ConcurrentMap to be converted.
- * @return A Scala mutable ConcurrentMap view of the argument.
- */
- implicit def javaConcurrentMapAsScalaConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): concurrent.Map[A, B] = m match {
- case cmw: ScalaConcurrentMapWrapper[a, b] => cmw.underlying
- case _ => new JavaConcurrentMapWrapper(m)
- }
-
-
- /**
- * Implicitly converts a Java `Dictionary` to a Scala mutable
- * `Map[String, String]`.
- *
- * The returned Scala `Map[String, String]` is backed by the provided Java
- * `Dictionary` and any side-effects of using it via the Scala interface
- * will be visible via the Java interface and vice versa.
- *
- * @param m The Dictionary to be converted.
- * @return A Scala mutable Map[String, String] view of the argument.
- */
- implicit def dictionaryAsScalaMap[A, B](p: ju.Dictionary[A, B]): mutable.Map[A, B] = p match {
- case DictionaryWrapper(wrapped) => wrapped
- case _ => new JDictionaryWrapper(p)
- }
-
- /**
- * Implicitly converts a Java `Properties` to a Scala `mutable Map[String, String]`.
- *
- * The returned Scala `Map[String, String]` is backed by the provided Java
- * `Properties` and any side-effects of using it via the Scala interface
- * will be visible via the Java interface and vice versa.
- *
- * @param m The Properties to be converted.
- * @return A Scala mutable Map[String, String] view of the argument.
- */
- implicit def propertiesAsScalaMap(p: ju.Properties): mutable.Map[String, String] = p match {
- case _ => new JPropertiesWrapper(p)
- }
-
@deprecated("use propertiesAsScalaMap instead", "2.9.0")
def asScalaMap(p: ju.Properties): mutable.Map[String, String] = propertiesAsScalaMap(p)
+}
- // Private implementations (shared by JavaConverters) ...
-
- trait IterableWrapperTrait[A] extends ju.AbstractCollection[A] {
- val underlying: Iterable[A]
- def size = underlying.size
- override def iterator = IteratorWrapper(underlying.iterator)
- override def isEmpty = underlying.isEmpty
- }
-
- case class IteratorWrapper[A](underlying: Iterator[A])
- extends ju.Iterator[A] with ju.Enumeration[A] {
- def hasNext = underlying.hasNext
- def next() = underlying.next
- def hasMoreElements = underlying.hasNext
- def nextElement() = underlying.next
- def remove() = throw new UnsupportedOperationException
- }
-
- class ToIteratorWrapper[A](underlying : Iterator[A]) {
- def asJava = new IteratorWrapper(underlying)
- }
-
- case class JIteratorWrapper[A](underlying: ju.Iterator[A]) extends AbstractIterator[A] with Iterator[A] {
- def hasNext = underlying.hasNext
- def next() = underlying.next
- }
-
- case class JEnumerationWrapper[A](underlying: ju.Enumeration[A]) extends AbstractIterator[A] with Iterator[A] {
- def hasNext = underlying.hasMoreElements
- def next() = underlying.nextElement
- }
-
- case class IterableWrapper[A](underlying: Iterable[A])
- extends ju.AbstractCollection[A]
- with IterableWrapperTrait[A] { }
-
- case class JIterableWrapper[A](underlying: jl.Iterable[A]) extends AbstractIterable[A] with Iterable[A] {
- def iterator = underlying.iterator
- def newBuilder[B] = new mutable.ArrayBuffer[B]
- }
-
- case class JCollectionWrapper[A](underlying: ju.Collection[A]) extends AbstractIterable[A] with Iterable[A] {
- def iterator = underlying.iterator
- override def size = underlying.size
- override def isEmpty = underlying.isEmpty
- def newBuilder[B] = new mutable.ArrayBuffer[B]
- }
-
- case class SeqWrapper[A](underlying: Seq[A]) extends ju.AbstractList[A] with IterableWrapperTrait[A] {
- def get(i: Int) = underlying(i)
- }
-
- case class MutableSeqWrapper[A](underlying: mutable.Seq[A])
- extends ju.AbstractList[A] with IterableWrapperTrait[A] {
- def get(i: Int) = underlying(i)
- override def set(i: Int, elem: A) = {
- val p = underlying(i)
- underlying(i) = elem
- p
- }
- }
-
- case class MutableBufferWrapper[A](underlying: mutable.Buffer[A])
- extends ju.AbstractList[A] with IterableWrapperTrait[A] {
- def get(i: Int) = underlying(i)
- override def set(i: Int, elem: A) = { val p = underlying(i); underlying(i) = elem; p }
- override def add(elem: A) = { underlying append elem; true }
- override def remove(i: Int) = underlying remove i
- }
-
- case class JListWrapper[A](val underlying: ju.List[A]) extends mutable.AbstractBuffer[A] with mutable.Buffer[A] {
- def length = underlying.size
- override def isEmpty = underlying.isEmpty
- override def iterator: Iterator[A] = underlying.iterator
- def apply(i: Int) = underlying.get(i)
- def update(i: Int, elem: A) = underlying.set(i, elem)
- def +=:(elem: A) = { underlying.subList(0, 0) add elem; this }
- def +=(elem: A): this.type = { underlying add elem; this }
- def insertAll(i: Int, elems: Traversable[A]) = {
- val ins = underlying.subList(0, i)
- elems.seq.foreach(ins.add(_))
- }
- def remove(i: Int) = underlying.remove(i)
- def clear() = underlying.clear()
- def result = this
- }
-
- class SetWrapper[A](underlying: Set[A]) extends ju.AbstractSet[A] {
- self =>
- def size = underlying.size
- def iterator = new ju.Iterator[A] {
- val ui = underlying.iterator
- var prev: Option[A] = None
- def hasNext = ui.hasNext
- def next = { val e = ui.next; prev = Some(e); e }
- def remove = prev match {
- case Some(e) =>
- underlying match {
- case ms: mutable.Set[a] =>
- ms remove e
- prev = None
- case _ =>
- throw new UnsupportedOperationException("remove")
- }
- case _ =>
- throw new IllegalStateException("next must be called at least once before remove")
- }
- }
- }
-
- case class MutableSetWrapper[A](underlying: mutable.Set[A]) extends SetWrapper[A](underlying) {
- override def add(elem: A) = {
- val sz = underlying.size
- underlying += elem
- sz < underlying.size
- }
- override def remove(elem: AnyRef) =
- try underlying remove elem.asInstanceOf[A]
- catch { case ex: ClassCastException => false }
- override def clear() = underlying.clear()
- }
-
- case class JSetWrapper[A](underlying: ju.Set[A])
- extends mutable.AbstractSet[A]
- with mutable.Set[A]
- with mutable.SetLike[A, JSetWrapper[A]] {
-
- override def size = underlying.size
-
- def iterator = underlying.iterator
-
- def contains(elem: A): Boolean = underlying.contains(elem)
-
- def +=(elem: A): this.type = { underlying add elem; this }
- def -=(elem: A): this.type = { underlying remove elem; this }
-
- override def add(elem: A): Boolean = underlying add elem
- override def remove(elem: A): Boolean = underlying remove elem
- override def clear() = underlying.clear()
-
- override def empty = JSetWrapper(new ju.HashSet[A])
- }
-
- class MapWrapper[A, B](underlying: Map[A, B]) extends ju.AbstractMap[A, B] { self =>
- override def size = underlying.size
-
- override def get(key: AnyRef): B = try {
- underlying get key.asInstanceOf[A] match {
- case None => null.asInstanceOf[B]
- case Some(v) => v
- }
- } catch {
- case ex: ClassCastException => null.asInstanceOf[B]
- }
-
- override def entrySet: ju.Set[ju.Map.Entry[A, B]] = new ju.AbstractSet[ju.Map.Entry[A, B]] {
- def size = self.size
-
- def iterator = new ju.Iterator[ju.Map.Entry[A, B]] {
- val ui = underlying.iterator
- var prev : Option[A] = None
-
- def hasNext = ui.hasNext
-
- def next() = {
- val (k, v) = ui.next
- prev = Some(k)
- new ju.Map.Entry[A, B] {
- def getKey = k
- def getValue = v
- def setValue(v1 : B) = self.put(k, v1)
- override def hashCode = k.hashCode + v.hashCode
- override def equals(other: Any) = other match {
- case e: ju.Map.Entry[_, _] => k == e.getKey && v == e.getValue
- case _ => false
- }
- }
- }
-
- def remove() {
- prev match {
- case Some(k) =>
- underlying match {
- case mm: mutable.Map[a, _] =>
- mm remove k
- prev = None
- case _ =>
- throw new UnsupportedOperationException("remove")
- }
- case _ =>
- throw new IllegalStateException("next must be called at least once before remove")
- }
- }
- }
- }
- }
-
- case class MutableMapWrapper[A, B](underlying: mutable.Map[A, B])
- extends MapWrapper[A, B](underlying) {
- override def put(k: A, v: B) = underlying.put(k, v) match {
- case Some(v1) => v1
- case None => null.asInstanceOf[B]
- }
-
- override def remove(k: AnyRef): B = try {
- underlying remove k.asInstanceOf[A] match {
- case None => null.asInstanceOf[B]
- case Some(v) => v
- }
- } catch {
- case ex: ClassCastException => null.asInstanceOf[B]
- }
-
- override def clear() = underlying.clear()
- }
-
- trait JMapWrapperLike[A, B, +Repr <: mutable.MapLike[A, B, Repr] with mutable.Map[A, B]]
- extends mutable.Map[A, B] with mutable.MapLike[A, B, Repr] {
- def underlying: ju.Map[A, B]
-
- override def size = underlying.size
-
- def get(k: A) = {
- val v = underlying get k
- if (v != null)
- Some(v)
- else if (underlying containsKey k)
- Some(null.asInstanceOf[B])
- else
- None
- }
-
- def +=(kv: (A, B)): this.type = { underlying.put(kv._1, kv._2); this }
- def -=(key: A): this.type = { underlying remove key; this }
-
- override def put(k: A, v: B): Option[B] = {
- val r = underlying.put(k, v)
- if (r != null) Some(r) else None
- }
-
- override def update(k: A, v: B) { underlying.put(k, v) }
-
- override def remove(k: A): Option[B] = {
- val r = underlying remove k
- if (r != null) Some(r) else None
- }
-
- def iterator: Iterator[(A, B)] = new AbstractIterator[(A, B)] {
- val ui = underlying.entrySet.iterator
- def hasNext = ui.hasNext
- def next() = { val e = ui.next(); (e.getKey, e.getValue) }
- }
-
- override def clear() = underlying.clear()
-
- override def empty: Repr = null.asInstanceOf[Repr]
- }
-
- case class JMapWrapper[A, B](val underlying : ju.Map[A, B])
- extends mutable.AbstractMap[A, B] with JMapWrapperLike[A, B, JMapWrapper[A, B]] {
- override def empty = JMapWrapper(new ju.HashMap[A, B])
- }
-
- // will be removed in 2.11
- class ConcurrentMapWrapper[A, B](override val underlying: mutable.ConcurrentMap[A, B])
- extends MutableMapWrapper[A, B](underlying) with juc.ConcurrentMap[A, 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) = try {
- underlying.remove(k.asInstanceOf[A], v.asInstanceOf[B])
- } catch {
- case ex: ClassCastException =>
- false
- }
-
- 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)
- }
-
- class ScalaConcurrentMapWrapper[A, B](override val underlying: concurrent.Map[A, B])
- extends MutableMapWrapper[A, B](underlying) with juc.ConcurrentMap[A, 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) = try {
- underlying.remove(k.asInstanceOf[A], v.asInstanceOf[B])
- } catch {
- case ex: ClassCastException =>
- false
- }
-
- 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)
- }
-
- // will be removed in 2.11
- case class JConcurrentMapWrapper[A, B](val underlying: juc.ConcurrentMap[A, B])
- extends mutable.AbstractMap[A, B] with JMapWrapperLike[A, B, JConcurrentMapWrapper[A, B]] 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 JavaConcurrentMapWrapper[A, B](val underlying: juc.ConcurrentMap[A, B])
- extends mutable.AbstractMap[A, B] with JMapWrapperLike[A, B, JConcurrentMapWrapper[A, B]] with concurrent.Map[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 DictionaryWrapper[A, B](underlying: mutable.Map[A, B])
- extends ju.Dictionary[A, B] {
- def size: Int = underlying.size
- def isEmpty: Boolean = underlying.isEmpty
- def keys: ju.Enumeration[A] = asJavaEnumeration(underlying.keysIterator)
- def elements: ju.Enumeration[B] = asJavaEnumeration(underlying.valuesIterator)
- def get(key: AnyRef) = try {
- underlying get key.asInstanceOf[A] match {
- case None => null.asInstanceOf[B]
- case Some(v) => v
- }
- } catch {
- case ex: ClassCastException => null.asInstanceOf[B]
- }
- def put(key: A, value: B): B = underlying.put(key, value) match {
- case Some(v) => v
- case None => null.asInstanceOf[B]
- }
- override def remove(key: AnyRef) = try {
- underlying remove key.asInstanceOf[A] match {
- case None => null.asInstanceOf[B]
- case Some(v) => v
- }
- } catch {
- case ex: ClassCastException => null.asInstanceOf[B]
- }
- }
-
- case class JDictionaryWrapper[A, B](underlying: ju.Dictionary[A, B])
- extends mutable.AbstractMap[A, B] with mutable.Map[A, B] {
- override def size: Int = underlying.size
-
- def get(k: A) = {
- val v = underlying get k
- if (v != null) Some(v) else None
- }
-
- def +=(kv: (A, B)): this.type = { underlying.put(kv._1, kv._2); this }
- def -=(key: A): this.type = { underlying remove key; this }
-
- override def put(k: A, v: B): Option[B] = {
- val r = underlying.put(k, v)
- if (r != null) Some(r) else None
- }
-
- override def update(k: A, v: B) { underlying.put(k, v) }
-
- override def remove(k: A): Option[B] = {
- val r = underlying remove k
- if (r != null) Some(r) else None
- }
-
- def iterator = enumerationAsScalaIterator(underlying.keys) map (k => (k, underlying get k))
-
- override def clear() = underlying.clear()
- }
-
- case class JPropertiesWrapper(underlying: ju.Properties)
- extends mutable.AbstractMap[String, String]
- with 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: Iterator[(String, String)] = new AbstractIterator[(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/JavaConverters.scala b/src/library/scala/collection/JavaConverters.scala
index d56a6baff6..f8a9466caf 100755
--- a/src/library/scala/collection/JavaConverters.scala
+++ b/src/library/scala/collection/JavaConverters.scala
@@ -8,7 +8,15 @@
package scala.collection
-/** A collection of decorators that allow to convert between
+import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc }
+import convert._
+
+// TODO: I cleaned all this documentation up in JavaConversions, but the
+// documentation in here is basically the pre-cleaned-up version with minor
+// additions. Would be nice to have in one place.
+
+
+/** A collection of decorators that allow converting between
* Scala and Java collections using `asScala` and `asJava` methods.
*
* The following conversions are supported via `asJava`, `asScala`
@@ -48,502 +56,48 @@ package scala.collection
* @author Martin Odersky
* @since 2.8.1
*/
-
-trait JavaConverters {
- import java.{ lang => jl, util => ju }
- import java.util.{ concurrent => juc }
- import JavaConversions._
-
- // TODO: I cleaned all this documentation up in JavaConversions, but the
- // documentation in here is basically the pre-cleaned-up version with minor
- // additions. Would be nice to have in one place.
-
- // Conversion decorator classes
-
- /** Generic class containing the `asJava` converter method */
- class AsJava[C](op: => C) {
- /** Converts a Scala collection to the corresponding Java collection */
- def asJava: C = op
- }
-
- /** Generic class containing the `asScala` converter method */
- class AsScala[C](op: => C) {
- /** Converts a Java collection to the corresponding Scala collection */
- def asScala: C = op
- }
-
- /** Generic class containing the `asJavaCollection` converter method */
- class AsJavaCollection[A](i: Iterable[A]) {
- /** Converts a Scala `Iterable` to a Java `Collection` */
- def asJavaCollection: ju.Collection[A] = JavaConversions.asJavaCollection(i)
- }
-
- /** Generic class containing the `asJavaEnumeration` converter method */
- class AsJavaEnumeration[A](i: Iterator[A]) {
- /** Converts a Scala `Iterator` to a Java `Enumeration` */
- def asJavaEnumeration: ju.Enumeration[A] = JavaConversions.asJavaEnumeration(i)
- }
-
- /** Generic class containing the `asJavaDictionary` converter method */
- class AsJavaDictionary[A, B](m : mutable.Map[A, B]) {
- /** Converts a Scala `Map` to a Java `Dictionary` */
- def asJavaDictionary: ju.Dictionary[A, B] = JavaConversions.asJavaDictionary(m)
- }
-
- // Scala => Java
-
- /**
- * Adds an `asJava` method that implicitly converts a Scala `Iterator` to a
- * Java `Iterator`. The returned Java `Iterator` is backed by the provided Scala
- * `Iterator` and any side-effects of using it via the Java interface will
- * be visible via the Scala interface and vice versa.
- *
- * If the Scala `Iterator` was previously obtained from an implicit or explicit
- * call of `asIterator(java.util.Iterator)` then the original Java `Iterator`
- * will be returned by the `asJava` method.
- *
- * @param i The `Iterator` to be converted.
- * @return An object with an `asJava` method that returns a Java `Iterator` view of the argument.
- */
- implicit def asJavaIteratorConverter[A](i : Iterator[A]): AsJava[ju.Iterator[A]] =
- new AsJava(asJavaIterator(i))
-
- /**
- * Adds an `asJavaEnumeration` method that implicitly converts a Scala
- * `Iterator` to a Java `Enumeration`. The returned Java `Enumeration` is
- * backed by the provided Scala `Iterator` and any side-effects of using
- * it via the Java interface will be visible via the Scala interface and
- * vice versa.
- *
- * If the Scala `Iterator` was previously obtained from an implicit or
- * explicit call of `asIterator(java.util.Enumeration)` then the
- * original Java `Enumeration` will be returned.
- *
- * @param i The `Iterator` to be converted.
- * @return An object with an `asJavaEnumeration` method that returns a Java
- * `Enumeration` view of the argument.
- */
- implicit def asJavaEnumerationConverter[A](i : Iterator[A]): AsJavaEnumeration[A] =
- new AsJavaEnumeration(i)
-
- /**
- * Adds an `asJava` method that implicitly converts a Scala `Iterable` to
- * a Java `Iterable`.
- *
- * The returned Java `Iterable` is backed by the provided Scala `Iterable`
- * and any side-effects of using it via the Java interface will be visible
- * via the Scala interface and vice versa.
- *
- * If the Scala `Iterable` was previously obtained from an implicit or
- * explicit call of `asIterable(java.lang.Iterable)` then the original
- * Java `Iterable` will be returned.
- *
- * @param i The `Iterable` to be converted.
- * @return An object with an `asJavaCollection` method that returns a Java
- * `Iterable` view of the argument.
- */
- implicit def asJavaIterableConverter[A](i : Iterable[A]): AsJava[jl.Iterable[A]] =
- new AsJava(asJavaIterable(i))
-
- /**
- * Adds an `asJavaCollection` method that implicitly converts a Scala
- * `Iterable` to an immutable Java `Collection`.
- *
- * If the Scala `Iterable` was previously obtained from an implicit or
- * explicit call of `asSizedIterable(java.util.Collection)` then the
- * original Java `Collection` will be returned.
- *
- * @param i The `SizedIterable` to be converted.
- * @return An object with an `asJava` method that returns a Java
- * `Collection` view of the argument.
- */
- implicit def asJavaCollectionConverter[A](i : Iterable[A]): AsJavaCollection[A] =
- new AsJavaCollection(i)
-
- /**
- * Adds an `asJava` method that implicitly converts a Scala mutable `Buffer`
- * to a Java `List`.
- *
- * The returned Java `List` is backed by the provided Scala `Buffer` and any
- * side-effects of using it via the Java interface will be visible via the
- * Scala interface and vice versa.
- *
- * If the Scala `Buffer` was previously obtained from an implicit or explicit
- * call of `asBuffer(java.util.List)` then the original Java `List` will be
- * returned.
- *
- * @param b The `Buffer` to be converted.
- * @return An object with an `asJava` method that returns a Java `List` view
- * of the argument.
- */
- implicit def bufferAsJavaListConverter[A](b : mutable.Buffer[A]): AsJava[ju.List[A]] =
- new AsJava(bufferAsJavaList(b))
-
- /**
- * Adds an `asJava` method that implicitly converts a Scala mutable `Seq`
- * to a Java `List`.
- *
- * The returned Java `List` is backed by the provided Scala `Seq` and any
- * side-effects of using it via the Java interface will be visible via the
- * Scala interface and vice versa.
- *
- * If the Scala `Seq` was previously obtained from an implicit or explicit
- * call of `asSeq(java.util.List)` then the original Java `List` will be
- * returned.
- *
- * @param b The `Seq` to be converted.
- * @return An object with an `asJava` method that returns a Java `List`
- * view of the argument.
- */
- implicit def mutableSeqAsJavaListConverter[A](b : mutable.Seq[A]): AsJava[ju.List[A]] =
- new AsJava(mutableSeqAsJavaList(b))
-
- /**
- * Adds an `asJava` method that implicitly converts a Scala `Seq` to a
- * Java `List`.
- *
- * The returned Java `List` is backed by the provided Scala `Seq` and any
- * side-effects of using it via the Java interface will be visible via the
- * Scala interface and vice versa.
- *
- * If the Scala `Seq` was previously obtained from an implicit or explicit
- * call of `asSeq(java.util.List)` then the original Java `List` will be
- * returned.
- *
- * @param b The `Seq` to be converted.
- * @return An object with an `asJava` method that returns a Java `List`
- * view of the argument.
- */
- implicit def seqAsJavaListConverter[A](b : Seq[A]): AsJava[ju.List[A]] =
- new AsJava(seqAsJavaList(b))
+object JavaConverters extends DecorateAsJava with DecorateAsScala {
+ @deprecated("Don't access these decorators directly.", "2.10.0")
+ type AsJava[A] = Decorators.AsJava[A]
+ @deprecated("Don't access these decorators directly.", "2.10.0")
+ type AsScala[A] = Decorators.AsScala[A]
+ @deprecated("Don't access these decorators directly.", "2.10.0")
+ type AsJavaCollection[A] = Decorators.AsJavaCollection[A]
+ @deprecated("Don't access these decorators directly.", "2.10.0")
+ type AsJavaEnumeration[A] = Decorators.AsJavaEnumeration[A]
+ @deprecated("Don't access these decorators directly.", "2.10.0")
+ type AsJavaDictionary[A, B] = Decorators.AsJavaDictionary[A, B]
@deprecated("Use bufferAsJavaListConverter instead", "2.9.0")
def asJavaListConverter[A](b : mutable.Buffer[A]): AsJava[ju.List[A]] = bufferAsJavaListConverter(b)
+
@deprecated("Use mutableSeqAsJavaListConverter instead", "2.9.0")
def asJavaListConverter[A](b : mutable.Seq[A]): AsJava[ju.List[A]] = mutableSeqAsJavaListConverter(b)
+
@deprecated("Use seqAsJavaListConverter instead", "2.9.0")
def asJavaListConverter[A](b : Seq[A]): AsJava[ju.List[A]] = seqAsJavaListConverter(b)
- /**
- * Adds an `asJava` method that implicitly converts a Scala mutable `Set`>
- * to a Java `Set`.
- *
- * The returned Java `Set` is backed by the provided Scala `Set` and any
- * side-effects of using it via the Java interface will be visible via
- * the Scala interface and vice versa.
- *
- * If the Scala `Set` was previously obtained from an implicit or explicit
- * call of `asSet(java.util.Set)` then the original Java `Set` will be
- * returned.
- *
- * @param s The `Set` to be converted.
- * @return An object with an `asJava` method that returns a Java `Set` view
- * of the argument.
- */
- implicit def mutableSetAsJavaSetConverter[A](s : mutable.Set[A]): AsJava[ju.Set[A]] =
- new AsJava(mutableSetAsJavaSet(s))
-
@deprecated("Use mutableSetAsJavaSetConverter instead", "2.9.0")
def asJavaSetConverter[A](s : mutable.Set[A]): AsJava[ju.Set[A]] = mutableSetAsJavaSetConverter(s)
- /**
- * Adds an `asJava` method that implicitly converts a Scala `Set` to a
- * Java `Set`.
- *
- * The returned Java `Set` is backed by the provided Scala `Set` and any
- * side-effects of using it via the Java interface will be visible via
- * the Scala interface and vice versa.
- *
- * If the Scala `Set` was previously obtained from an implicit or explicit
- * call of `asSet(java.util.Set)` then the original Java `Set` will be
- * returned.
- *
- * @param s The `Set` to be converted.
- * @return An object with an `asJava` method that returns a Java `Set` view
- * of the argument.
- */
- implicit def setAsJavaSetConverter[A](s : Set[A]): AsJava[ju.Set[A]] =
- new AsJava(setAsJavaSet(s))
-
@deprecated("Use setAsJavaSetConverter instead", "2.9.0")
def asJavaSetConverter[A](s : Set[A]): AsJava[ju.Set[A]] = setAsJavaSetConverter(s)
- /**
- * Adds an `asJava` method that implicitly converts a Scala mutable `Map`
- * to a Java `Map`.
- *
- * The returned Java `Map` is backed by the provided Scala `Map` and any
- * side-effects of using it via the Java interface will be visible via the
- * Scala interface and vice versa.
- *
- * If the Scala `Map` was previously obtained from an implicit or explicit
- * call of `asMap(java.util.Map)` then the original Java `Map` will be
- * returned.
- *
- * @param m The `Map` to be converted.
- * @return An object with an `asJava` method that returns a Java `Map` view
- * of the argument.
- */
- implicit def mutableMapAsJavaMapConverter[A, B](m : mutable.Map[A, B]): AsJava[ju.Map[A, B]] =
- new AsJava(mutableMapAsJavaMap(m))
-
@deprecated("use mutableMapAsJavaMapConverter instead", "2.9.0")
def asJavaMapConverter[A, B](m : mutable.Map[A, B]): AsJava[ju.Map[A, B]] = mutableMapAsJavaMapConverter(m)
- /**
- * Adds an `asJavaDictionary` method that implicitly converts a Scala
- * mutable `Map` to a Java `Dictionary`.
- *
- * The returned Java `Dictionary` is backed by the provided Scala
- * `Dictionary` and any side-effects of using it via the Java interface
- * will be visible via the Scala interface and vice versa.
- *
- * If the Scala `Dictionary` was previously obtained from an implicit or
- * explicit call of `asMap(java.util.Dictionary)` then the original
- * Java `Dictionary` will be returned.
- *
- * @param m The `Map` to be converted.
- * @return An object with an `asJavaDictionary` method that returns a
- * Java `Dictionary` view of the argument.
- */
- implicit def asJavaDictionaryConverter[A, B](m : mutable.Map[A, B]): AsJavaDictionary[A, B] =
- new AsJavaDictionary(m)
-
- /**
- * Adds an `asJava` method that implicitly converts a Scala `Map` to
- * a Java `Map`.
- *
- * The returned Java `Map` is backed by the provided Scala `Map` and any
- * side-effects of using it via the Java interface will be visible via
- * the Scala interface and vice versa.
- *
- * If the Scala `Map` was previously obtained from an implicit or explicit
- * call of `asMap(java.util.Map)` then the original Java `Map` will be
- * returned.
- *
- * @param m The `Map` to be converted.
- * @return An object with an `asJava` method that returns a Java `Map` view
- * of the argument.
- */
- implicit def mapAsJavaMapConverter[A, B](m : Map[A, B]): AsJava[ju.Map[A, B]] =
- new AsJava(mapAsJavaMap(m))
-
@deprecated("Use mapAsJavaMapConverter instead", "2.9.0")
def asJavaMapConverter[A, B](m : Map[A, B]): AsJava[ju.Map[A, B]] = mapAsJavaMapConverter(m)
- @deprecated("Use `concurrent.Map` instead of `mutable.ConcurrentMap`", "2.10.0")
- implicit def asJavaConcurrentMapConverter[A, B](m: mutable.ConcurrentMap[A, B]): AsJava[juc.ConcurrentMap[A, B]] =
- new AsJava(asJavaConcurrentMap(m))
-
- /**
- * Adds an `asJava` method that implicitly converts a Scala mutable
- * `concurrent.Map` to a Java `ConcurrentMap`.
- *
- * The returned Java `ConcurrentMap` is backed by the provided Scala
- * `concurrent.Map` and any side-effects of using it via the Java interface
- * will be visible via the Scala interface and vice versa.
- *
- * If the Scala `concurrent.Map` was previously obtained from an implicit or
- * explicit call of `asConcurrentMap(java.util.concurrent.ConcurrentMap)`
- * then the original Java `ConcurrentMap` will be returned.
- *
- * @param m The `concurrent.Map` to be converted.
- * @return An object with an `asJava` method that returns a Java
- * `ConcurrentMap` view of the argument.
- */
- implicit def asJavaConcurrentMapConverter[A, B](m: concurrent.Map[A, B]): AsJava[juc.ConcurrentMap[A, B]] =
- new AsJava(asJavaConcurrentMap(m))
-
- /**
- * Adds an `asScala` method that implicitly converts a Java `Iterator` to
- * a Scala `Iterator`.
- *
- * The returned Scala `Iterator` is backed by the provided Java `Iterator`
- * and any side-effects of using it via the Scala interface will be visible
- * via the Java interface and vice versa.
- *
- * If the Java `Iterator` was previously obtained from an implicit or
- * explicit call of `asIterator(scala.collection.Iterator)` then the
- * original Scala `Iterator` will be returned.
- *
- * @param i The `Iterator` to be converted.
- * @return An object with an `asScala` method that returns a Scala
- * `Iterator` view of the argument.
- */
- implicit def asScalaIteratorConverter[A](i : ju.Iterator[A]): AsScala[Iterator[A]] =
- new AsScala(asScalaIterator(i))
-
- /**
- * Adds an `asScala` method that implicitly converts a Java `Enumeration`
- * to a Scala `Iterator`.
- *
- * The returned Scala `Iterator` is backed by the provided Java
- * `Enumeration` and any side-effects of using it via the Scala interface
- * will be visible via the Java interface and vice versa.
- *
- * If the Java `Enumeration` was previously obtained from an implicit or
- * explicit call of `asEnumeration(scala.collection.Iterator)` then the
- * original Scala `Iterator` will be returned.
- *
- * @param i The `Enumeration` to be converted.
- * @return An object with an `asScala` method that returns a Scala
- * `Iterator` view of the argument.
- */
- implicit def enumerationAsScalaIteratorConverter[A](i : ju.Enumeration[A]): AsScala[Iterator[A]] =
- new AsScala(enumerationAsScalaIterator(i))
-
- /**
- * Adds an `asScala` method that implicitly converts a Java `Iterable` to
- * a Scala `Iterable`.
- *
- * The returned Scala `Iterable` is backed by the provided Java `Iterable`
- * and any side-effects of using it via the Scala interface will be visible
- * via the Java interface and vice versa.
- *
- * If the Java `Iterable` was previously obtained from an implicit or
- * explicit call of `asIterable(scala.collection.Iterable)` then the original
- * Scala `Iterable` will be returned.
- *
- * @param i The `Iterable` to be converted.
- * @return An object with an `asScala` method that returns a Scala `Iterable`
- * view of the argument.
- */
- implicit def iterableAsScalaIterableConverter[A](i : jl.Iterable[A]): AsScala[Iterable[A]] =
- new AsScala(iterableAsScalaIterable(i))
-
@deprecated("Use iterableAsScalaIterableConverter instead", "2.9.0")
def asScalaIterableConverter[A](i : jl.Iterable[A]): AsScala[Iterable[A]] = iterableAsScalaIterableConverter(i)
- /**
- * Adds an `asScala` method that implicitly converts a Java `Collection` to
- * an Scala `Iterable`.
- *
- * If the Java `Collection` was previously obtained from an implicit or
- * explicit call of `asCollection(scala.collection.SizedIterable)` then
- * the original Scala `SizedIterable` will be returned.
- *
- * @param i The `Collection` to be converted.
- * @return An object with an `asScala` method that returns a Scala
- * `SizedIterable` view of the argument.
- */
- implicit def collectionAsScalaIterableConverter[A](i : ju.Collection[A]): AsScala[Iterable[A]] =
- new AsScala(collectionAsScalaIterable(i))
-
@deprecated("Use collectionAsScalaIterableConverter instead", "2.9.0")
def asScalaIterableConverter[A](i : ju.Collection[A]): AsScala[Iterable[A]] = collectionAsScalaIterableConverter(i)
- /**
- * Adds an `asScala` method that implicitly converts a Java `List` to a
- * Scala mutable `Buffer`.
- *
- * The returned Scala `Buffer` is backed by the provided Java `List` and
- * any side-effects of using it via the Scala interface will be visible via
- * the Java interface and vice versa.
- *
- * If the Java `List` was previously obtained from an implicit or explicit
- * call of `asList(scala.collection.mutable.Buffer)` then the original
- * Scala `Buffer` will be returned.
- *
- * @param l The `List` to be converted.
- * @return An object with an `asScala` method that returns a Scala mutable
- * `Buffer` view of the argument.
- */
- implicit def asScalaBufferConverter[A](l : ju.List[A]): AsScala[mutable.Buffer[A]] =
- new AsScala(asScalaBuffer(l))
-
- /**
- * Adds an `asScala` method that implicitly converts a Java `Set` to a
- * Scala mutable `Set`.
- *
- * The returned Scala `Set` is backed by the provided Java `Set` and any
- * side-effects of using it via the Scala interface will be visible via
- * the Java interface and vice versa.
- *
- * If the Java `Set` was previously obtained from an implicit or explicit
- * call of `asSet(scala.collection.mutable.Set)` then the original
- * Scala `Set` will be returned.
- *
- * @param s The `Set` to be converted.
- * @return An object with an `asScala` method that returns a Scala mutable
- * `Set` view of the argument.
- */
- implicit def asScalaSetConverter[A](s : ju.Set[A]): AsScala[mutable.Set[A]] =
- new AsScala(asScalaSet(s))
-
- /**
- * Adds an `asScala` method that implicitly converts a Java `Map` to a Scala
- * mutable `Map`. The returned Scala `Map` is backed by the provided Java
- * `Map` and any side-effects of using it via the Scala interface will
- * be visible via the Java interface and vice versa.
- *
- * If the Java `Map` was previously obtained from an implicit or explicit
- * call of `asMap(scala.collection.mutable.Map)` then the original
- * Scala `Map` will be returned.
- *
- * @param m The `Map` to be converted.
- * @return An object with an `asScala` method that returns a Scala mutable
- * `Map` view of the argument.
- */
- implicit def mapAsScalaMapConverter[A, B](m : ju.Map[A, B]): AsScala[mutable.Map[A, B]] =
- new AsScala(mapAsScalaMap(m))
-
@deprecated("Use mapAsScalaMapConverter instead", "2.9.0")
def asScalaMapConverter[A, B](m : ju.Map[A, B]): AsScala[mutable.Map[A, B]] = mapAsScalaMapConverter(m)
- @deprecated("Use `javaConcurrentMapAsScalaConcurrentMapConverter` instead, and use `concurrent.Map` instead of `mutable.ConcurrentMap`", "2.10.0")
- def asScalaConcurrentMapConverter[A, B](m: juc.ConcurrentMap[A, B]): AsScala[mutable.ConcurrentMap[A, B]] =
- new AsScala(asScalaConcurrentMap(m))
-
- /**
- * Adds an `asScala` method that implicitly converts a Java `ConcurrentMap`
- * to a Scala mutable `concurrent.Map`. The returned Scala `concurrent.Map` is
- * backed by the provided Java `ConcurrentMap` and any side-effects of using
- * it via the Scala interface will be visible via the Java interface and
- * vice versa.
- *
- * If the Java `ConcurrentMap` was previously obtained from an implicit or
- * explicit call of `asConcurrentMap(scala.collection.mutable.ConcurrentMap)`
- * then the original Scala `concurrent.Map` will be returned.
- *
- * @param m The `ConcurrentMap` to be converted.
- * @return An object with an `asScala` method that returns a Scala mutable
- * `concurrent.Map` view of the argument.
- */
- implicit def javaConcurrentMapAsScalaConcurrentMapConverter[A, B](m: juc.ConcurrentMap[A, B]): AsScala[concurrent.Map[A, B]] =
- new AsScala(javaConcurrentMapAsScalaConcurrentMap(m))
-
- /**
- * Adds an `asScala` method that implicitly converts a Java `Dictionary`
- * to a Scala mutable `Map[String, String]`. The returned Scala
- * `Map[String, String]` is backed by the provided Java `Dictionary` and
- * any side-effects of using it via the Scala interface will be visible via
- * the Java interface and vice versa.
- *
- * @param m The `Dictionary` to be converted.
- * @return An object with an `asScala` method that returns a Scala mutable
- * `Map[String, String]` view of the argument.
- */
- implicit def dictionaryAsScalaMapConverter[A, B](p: ju.Dictionary[A, B]): AsScala[mutable.Map[A, B]] =
- new AsScala(dictionaryAsScalaMap(p))
-
- /**
- * Adds an `asScala` method that implicitly converts a Java `Properties`
- * to a Scala mutable `Map[String, String]`. The returned Scala
- * `Map[String, String]` is backed by the provided Java `Properties` and
- * any side-effects of using it via the Scala interface will be visible via
- * the Java interface and vice versa.
- *
- * @param m The `Properties` to be converted.
- * @return An object with an `asScala` method that returns a Scala mutable
- * `Map[String, String]` view of the argument.
- */
- implicit def propertiesAsScalaMapConverter(p: ju.Properties): AsScala[mutable.Map[String, String]] =
- new AsScala(propertiesAsScalaMap(p))
-
@deprecated("Use propertiesAsScalaMapConverter instead", "2.9.0")
- def asScalaMapConverter(p: ju.Properties): AsScala[mutable.Map[String, String]] =
- propertiesAsScalaMapConverter(p)
-
+ def asScalaMapConverter(p: ju.Properties): AsScala[mutable.Map[String, String]] = propertiesAsScalaMapConverter(p)
}
-
-object JavaConverters extends JavaConverters
diff --git a/src/library/scala/collection/MapLike.scala b/src/library/scala/collection/MapLike.scala
index 07116e99dd..8f88e62791 100644
--- a/src/library/scala/collection/MapLike.scala
+++ b/src/library/scala/collection/MapLike.scala
@@ -91,14 +91,18 @@ self =>
* @param kv the key/value pair
* @tparam B1 the type of the value in the key/value pair.
* @return a new map with the new binding added to this map
+ *
* @usecase def + (kv: (A, B)): Map[A, B]
+ * @inheritdoc
*/
def + [B1 >: B] (kv: (A, B1)): Map[A, B1]
/** Removes a key from this map, returning a new map.
* @param key the key to be removed
* @return a new map without a binding for `key`
+ *
* @usecase def - (key: A): Map[A, B]
+ * @inheritdoc
*/
def - (key: A): This
@@ -115,7 +119,9 @@ self =>
* @tparam B1 the result type of the default computation.
* @return the value associated with `key` if it exists,
* otherwise the result of the `default` computation.
+ *
* @usecase def getOrElse(key: A, default: => B): B
+ * @inheritdoc
*/
def getOrElse[B1 >: B](key: A, default: => B1): B1 = get(key) match {
case Some(v) => v
@@ -255,7 +261,9 @@ self =>
* @param value the value
* @tparam B1 the type of the added value
* @return A new map with the new key/value mapping added to this map.
+ *
* @usecase def updated(key: A, value: B): Map[A, B]
+ * @inheritdoc
*/
def updated [B1 >: B](key: A, value: B1): Map[A, B1] = this + ((key, value))
@@ -269,8 +277,10 @@ self =>
* @param kvs the remaining key/value pairs
* @tparam B1 the type of the added values
* @return a new map with the given bindings added to this map
+ *
* @usecase def + (kvs: (A, B)*): Map[A, B]
- * @param the key/value pairs
+ * @inheritdoc
+ * @param the key/value pairs
*/
def + [B1 >: B] (kv1: (A, B1), kv2: (A, B1), kvs: (A, B1) *): Map[A, B1] =
this + kv1 + kv2 ++ kvs
@@ -280,7 +290,9 @@ self =>
* @param kvs the collection containing the added key/value pairs
* @tparam B1 the type of the added values
* @return a new map with the given bindings added to this map
+ *
* @usecase def ++ (xs: Traversable[(A, B)]): Map[A, B]
+ * @inheritdoc
*/
def ++[B1 >: B](xs: GenTraversableOnce[(A, B1)]): Map[A, B1] =
((repr: Map[A, B1]) /: xs.seq) (_ + _)
diff --git a/src/library/scala/collection/SeqLike.scala b/src/library/scala/collection/SeqLike.scala
index 526ea7e240..fd1d42d7e9 100644
--- a/src/library/scala/collection/SeqLike.scala
+++ b/src/library/scala/collection/SeqLike.scala
@@ -410,13 +410,6 @@ trait SeqLike[+A, +Repr] extends Any with IterableLike[A, Repr] with GenSeqLike[
/** Produces a new sequence which contains all elements of this $coll and also all elements of
* a given sequence. `xs union ys` is equivalent to `xs ++ ys`.
- * $willNotTerminateInf
- *
- * Another way to express this
- * is that `xs union ys` computes the order-presevring multi-set union of `xs` and `ys`.
- * `union` is hence a counter-part of `diff` and `intersect` which also work on multi-sets.
- *
- * $willNotTerminateInf
*
* @param that the sequence to add.
* @tparam B the element type of the returned $coll.
@@ -425,14 +418,21 @@ trait SeqLike[+A, +Repr] extends Any with IterableLike[A, Repr] with GenSeqLike[
* @return a new collection of type `That` which contains all elements of this $coll
* followed by all elements of `that`.
* @usecase def union(that: Seq[A]): $Coll[A]
- * @return a new $coll which contains all elements of this $coll
- * followed by all elements of `that`.
+ * @inheritdoc
+ *
+ * Another way to express this
+ * is that `xs union ys` computes the order-presevring multi-set union of `xs` and `ys`.
+ * `union` is hence a counter-part of `diff` and `intersect` which also work on multi-sets.
+ *
+ * $willNotTerminateInf
+ *
+ * @return a new $coll which contains all elements of this $coll
+ * followed by all elements of `that`.
*/
override def union[B >: A, That](that: GenSeq[B])(implicit bf: CanBuildFrom[Repr, B, That]): That =
this ++ that
/** Computes the multiset difference between this $coll and another sequence.
- * $willNotTerminateInf
*
* @param that the sequence of elements to remove
* @tparam B the element type of the returned $coll.
@@ -444,11 +444,15 @@ trait SeqLike[+A, +Repr] extends Any with IterableLike[A, Repr] with GenSeqLike[
* ''n'' times in `that`, then the first ''n'' occurrences of `x` will not form
* part of the result, but any following occurrences will.
* @usecase def diff(that: Seq[A]): $Coll[A]
- * @return a new $coll which contains all elements of this $coll
- * except some of occurrences of elements that also appear in `that`.
- * If an element value `x` appears
- * ''n'' times in `that`, then the first ''n'' occurrences of `x` will not form
- * part of the result, but any following occurrences will.
+ * @inheritdoc
+ *
+ * $willNotTerminateInf
+ *
+ * @return a new $coll which contains all elements of this $coll
+ * except some of occurrences of elements that also appear in `that`.
+ * If an element value `x` appears
+ * ''n'' times in `that`, then the first ''n'' occurrences of `x` will not form
+ * part of the result, but any following occurrences will.
*/
def diff[B >: A](that: GenSeq[B]): Repr = {
val occ = occCounts(that.seq)
@@ -463,7 +467,6 @@ trait SeqLike[+A, +Repr] extends Any with IterableLike[A, Repr] with GenSeqLike[
def diff[B >: A](that: Seq[B]): Repr = diff(that: GenSeq[B])
/** Computes the multiset intersection between this $coll and another sequence.
- * $mayNotTerminateInf
*
* @param that the sequence of elements to intersect with.
* @tparam B the element type of the returned $coll.
@@ -475,11 +478,15 @@ trait SeqLike[+A, +Repr] extends Any with IterableLike[A, Repr] with GenSeqLike[
* ''n'' times in `that`, then the first ''n'' occurrences of `x` will be retained
* in the result, but any following occurrences will be omitted.
* @usecase def intersect(that: Seq[A]): $Coll[A]
- * @return a new $coll which contains all elements of this $coll
- * which also appear in `that`.
- * If an element value `x` appears
- * ''n'' times in `that`, then the first ''n'' occurrences of `x` will be retained
- * in the result, but any following occurrences will be omitted.
+ * @inheritdoc
+ *
+ * $mayNotTerminateInf
+ *
+ * @return a new $coll which contains all elements of this $coll
+ * which also appear in `that`.
+ * If an element value `x` appears
+ * ''n'' times in `that`, then the first ''n'' occurrences of `x` will be retained
+ * in the result, but any following occurrences will be omitted.
*/
def intersect[B >: A](that: GenSeq[B]): Repr = {
val occ = occCounts(that.seq)
diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala
index 0da1cfb913..1f5beb5109 100644
--- a/src/library/scala/collection/TraversableLike.scala
+++ b/src/library/scala/collection/TraversableLike.scala
@@ -103,10 +103,6 @@ trait TraversableLike[+A, +Repr] extends Any
/** Applies a function `f` to all elements of this $coll.
*
- * Note: this method underlies the implementation of most other bulk operations.
- * It's important to implement this method in an efficient way.
- *
- *
* @param f the function that is applied for its side-effect to every element.
* The result of function `f` is discarded.
*
@@ -115,6 +111,11 @@ trait TraversableLike[+A, +Repr] extends Any
* but this is not necessary.
*
* @usecase def foreach(f: A => Unit): Unit
+ * @inheritdoc
+ *
+ * Note: this method underlies the implementation of most other bulk operations.
+ * It's important to implement this method in an efficient way.
+ *
*/
def foreach[U](f: A => U): Unit
@@ -165,17 +166,6 @@ trait TraversableLike[+A, +Repr] extends Any
* the resulting collection rather than the left one.
* Mnemonic: the COLon is on the side of the new COLlection type.
*
- * Example:
- * {{{
- * scala> val x = List(1)
- * x: List[Int] = List(1)
- *
- * scala> val y = LinkedList(2)
- * y: scala.collection.mutable.LinkedList[Int] = LinkedList(2)
- *
- * scala> val z = x ++: y
- * z: scala.collection.mutable.LinkedList[Int] = LinkedList(1, 2)
- * }}}
* @param that the traversable to append.
* @tparam B the element type of the returned collection.
* @tparam That $thatinfo
@@ -184,9 +174,22 @@ trait TraversableLike[+A, +Repr] extends Any
* of this $coll followed by all elements of `that`.
*
* @usecase def ++:[B](that: TraversableOnce[B]): $Coll[B]
- *
- * @return a new $coll which contains all elements of this $coll
- * followed by all elements of `that`.
+ * @inheritdoc
+ *
+ * Example:
+ * {{{
+ * scala> val x = List(1)
+ * x: List[Int] = List(1)
+ *
+ * scala> val y = LinkedList(2)
+ * y: scala.collection.mutable.LinkedList[Int] = LinkedList(2)
+ *
+ * scala> val z = x ++: y
+ * z: scala.collection.mutable.LinkedList[Int] = LinkedList(1, 2)
+ * }}}
+ *
+ * @return a new $coll which contains all elements of this $coll
+ * followed by all elements of `that`.
*/
def ++:[B >: A, That](that: TraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
val b = bf(repr)
@@ -284,11 +287,12 @@ trait TraversableLike[+A, +Repr] extends Any
* The order of the elements is preserved.
*
* @usecase def filterMap[B](f: A => Option[B]): $Coll[B]
+ * @inheritdoc
*
- * @param pf the partial function which filters and maps the $coll.
- * @return a new $coll resulting from applying the given option-valued function
- * `f` to each element and collecting all defined results.
- * The order of the elements is preserved.
+ * @param pf the partial function which filters and maps the $coll.
+ * @return a new $coll resulting from applying the given option-valued function
+ * `f` to each element and collecting all defined results.
+ * The order of the elements is preserved.
def filterMap[B, That](f: A => Option[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
val b = bf(repr)
for (x <- this)
@@ -588,8 +592,6 @@ trait TraversableLike[+A, +Repr] extends Any
* Copying will stop once either the end of the current $coll is reached,
* or the end of the array is reached, or `len` elements have been copied.
*
- * $willNotTerminateInf
- *
* @param xs the array to fill.
* @param start the starting index.
* @param len the maximal number of elements to copy.
@@ -597,6 +599,9 @@ trait TraversableLike[+A, +Repr] extends Any
*
*
* @usecase def copyToArray(xs: Array[A], start: Int, len: Int): Unit
+ * @inheritdoc
+ *
+ * $willNotTerminateInf
*/
def copyToArray[B >: A](xs: Array[B], start: Int, len: Int) {
var i = start
@@ -694,10 +699,11 @@ trait TraversableLike[+A, +Repr] extends Any
* that satisfies predicate `p` and collecting the results.
*
* @usecase def map[B](f: A => B): $Coll[B]
+ * @inheritdoc
*
- * @return a new $coll resulting from applying the given function
- * `f` to each element of the outer $coll that satisfies
- * predicate `p` and collecting the results.
+ * @return a new $coll resulting from applying the given function
+ * `f` to each element of the outer $coll that satisfies
+ * predicate `p` and collecting the results.
*/
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
val b = bf(repr)
@@ -710,9 +716,6 @@ trait TraversableLike[+A, +Repr] extends Any
* outer $coll containing this `WithFilter` instance that satisfy
* predicate `p` and concatenating the results.
*
- * The type of the resulting collection will be guided by the static type
- * of the outer $coll.
- *
* @param f the function to apply to each element.
* @tparam B the element type of the returned collection.
* @tparam That $thatinfo
@@ -723,11 +726,15 @@ trait TraversableLike[+A, +Repr] extends Any
* concatenating the results.
*
* @usecase def flatMap[B](f: A => TraversableOnce[B]): $Coll[B]
+ * @inheritdoc
+ *
+ * The type of the resulting collection will be guided by the static type
+ * of the outer $coll.
*
- * @return a new $coll resulting from applying the given
- * collection-valued function `f` to each element of the
- * outer $coll that satisfies predicate `p` and concatenating
- * the results.
+ * @return a new $coll resulting from applying the given
+ * collection-valued function `f` to each element of the
+ * outer $coll that satisfies predicate `p` and concatenating
+ * the results.
*/
def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
val b = bf(repr)
@@ -747,6 +754,7 @@ trait TraversableLike[+A, +Repr] extends Any
* but this is not necessary.
*
* @usecase def foreach(f: A => Unit): Unit
+ * @inheritdoc
*/
def foreach[U](f: A => U): Unit =
for (x <- self)
diff --git a/src/library/scala/collection/concurrent/TrieMap.scala b/src/library/scala/collection/concurrent/TrieMap.scala
index 092598e260..2a908aebb1 100644
--- a/src/library/scala/collection/concurrent/TrieMap.scala
+++ b/src/library/scala/collection/concurrent/TrieMap.scala
@@ -1027,7 +1027,7 @@ private[collection] class TrieMapIterator[K, V](var level: Int, private var ct:
Seq(this)
}
- def printDebug {
+ def printDebug() {
println("ctrie iterator")
println(stackpos.mkString(","))
println("depth: " + depth)
diff --git a/src/library/scala/collection/convert/DecorateAsJava.scala b/src/library/scala/collection/convert/DecorateAsJava.scala
new file mode 100644
index 0000000000..e05bfc41cd
--- /dev/null
+++ b/src/library/scala/collection/convert/DecorateAsJava.scala
@@ -0,0 +1,316 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2011, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.collection
+package convert
+
+import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc }
+import Decorators._
+import WrapAsJava._
+
+/** A collection of decorators that allow to convert between
+ * Scala and Java collections using `asScala` and `asJava` methods.
+ *
+ * The following conversions are supported via `asJava`, `asScala`
+ *
+ * - `scala.collection.Iterable` <=> `java.lang.Iterable`
+ * - `scala.collection.Iterator` <=> `java.util.Iterator`
+ * - `scala.collection.mutable.Buffer` <=> `java.util.List`
+ * - `scala.collection.mutable.Set` <=> `java.util.Set`
+ * - `scala.collection.mutable.Map` <=> `java.util.Map`
+ * - `scala.collection.mutable.ConcurrentMap` <=> `java.util.concurrent.ConcurrentMap`
+ *
+ * In all cases, converting from a source type to a target type and back
+ * again will return the original source object, e.g.
+ * {{{
+ * import scala.collection.JavaConverters._
+ *
+ * val sl = new scala.collection.mutable.ListBuffer[Int]
+ * val jl : java.util.List[Int] = sl.asJava
+ * val sl2 : scala.collection.mutable.Buffer[Int] = jl.asScala
+ * assert(sl eq sl2)
+ * }}}
+ * The following conversions also are supported, but the
+ * direction Scala to Java is done my a more specifically named method:
+ * `asJavaCollection`, `asJavaEnumeration`, `asJavaDictionary`.
+ *
+ * - `scala.collection.Iterable` <=> `java.util.Collection`
+ * - `scala.collection.Iterator` <=> `java.util.Enumeration`
+ * - `scala.collection.mutable.Map` <=> `java.util.Dictionary`
+ *
+ * In addition, the following one way conversions are provided via `asJava`:
+ *
+ * - `scala.collection.Seq` => `java.util.List`
+ * - `scala.collection.mutable.Seq` => `java.util.List`
+ * - `scala.collection.Set` => `java.util.Set`
+ * - `scala.collection.Map` => `java.util.Map`
+ *
+ * @author Martin Odersky
+ * @since 2.8.1
+ */
+
+trait DecorateAsJava {
+ /**
+ * Adds an `asJava` method that implicitly converts a Scala `Iterator` to a
+ * Java `Iterator`. The returned Java `Iterator` is backed by the provided Scala
+ * `Iterator` and any side-effects of using it via the Java interface will
+ * be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Iterator` was previously obtained from an implicit or explicit
+ * call of `asIterator(java.util.Iterator)` then the original Java `Iterator`
+ * will be returned by the `asJava` method.
+ *
+ * @param i The `Iterator` to be converted.
+ * @return An object with an `asJava` method that returns a Java `Iterator` view of the argument.
+ */
+ implicit def asJavaIteratorConverter[A](i : Iterator[A]): AsJava[ju.Iterator[A]] =
+ new AsJava(asJavaIterator(i))
+
+ /**
+ * Adds an `asJavaEnumeration` method that implicitly converts a Scala
+ * `Iterator` to a Java `Enumeration`. The returned Java `Enumeration` is
+ * backed by the provided Scala `Iterator` and any side-effects of using
+ * it via the Java interface will be visible via the Scala interface and
+ * vice versa.
+ *
+ * If the Scala `Iterator` was previously obtained from an implicit or
+ * explicit call of `asIterator(java.util.Enumeration)` then the
+ * original Java `Enumeration` will be returned.
+ *
+ * @param i The `Iterator` to be converted.
+ * @return An object with an `asJavaEnumeration` method that returns a Java
+ * `Enumeration` view of the argument.
+ */
+ implicit def asJavaEnumerationConverter[A](i : Iterator[A]): AsJavaEnumeration[A] =
+ new AsJavaEnumeration(i)
+
+ /**
+ * Adds an `asJava` method that implicitly converts a Scala `Iterable` to
+ * a Java `Iterable`.
+ *
+ * The returned Java `Iterable` is backed by the provided Scala `Iterable`
+ * and any side-effects of using it via the Java interface will be visible
+ * via the Scala interface and vice versa.
+ *
+ * If the Scala `Iterable` was previously obtained from an implicit or
+ * explicit call of `asIterable(java.lang.Iterable)` then the original
+ * Java `Iterable` will be returned.
+ *
+ * @param i The `Iterable` to be converted.
+ * @return An object with an `asJavaCollection` method that returns a Java
+ * `Iterable` view of the argument.
+ */
+ implicit def asJavaIterableConverter[A](i : Iterable[A]): AsJava[jl.Iterable[A]] =
+ new AsJava(asJavaIterable(i))
+
+ /**
+ * Adds an `asJavaCollection` method that implicitly converts a Scala
+ * `Iterable` to an immutable Java `Collection`.
+ *
+ * If the Scala `Iterable` was previously obtained from an implicit or
+ * explicit call of `asSizedIterable(java.util.Collection)` then the
+ * original Java `Collection` will be returned.
+ *
+ * @param i The `SizedIterable` to be converted.
+ * @return An object with an `asJava` method that returns a Java
+ * `Collection` view of the argument.
+ */
+ implicit def asJavaCollectionConverter[A](i : Iterable[A]): AsJavaCollection[A] =
+ new AsJavaCollection(i)
+
+ /**
+ * Adds an `asJava` method that implicitly converts a Scala mutable `Buffer`
+ * to a Java `List`.
+ *
+ * The returned Java `List` is backed by the provided Scala `Buffer` and any
+ * side-effects of using it via the Java interface will be visible via the
+ * Scala interface and vice versa.
+ *
+ * If the Scala `Buffer` was previously obtained from an implicit or explicit
+ * call of `asBuffer(java.util.List)` then the original Java `List` will be
+ * returned.
+ *
+ * @param b The `Buffer` to be converted.
+ * @return An object with an `asJava` method that returns a Java `List` view
+ * of the argument.
+ */
+ implicit def bufferAsJavaListConverter[A](b : mutable.Buffer[A]): AsJava[ju.List[A]] =
+ new AsJava(bufferAsJavaList(b))
+
+ /**
+ * Adds an `asJava` method that implicitly converts a Scala mutable `Seq`
+ * to a Java `List`.
+ *
+ * The returned Java `List` is backed by the provided Scala `Seq` and any
+ * side-effects of using it via the Java interface will be visible via the
+ * Scala interface and vice versa.
+ *
+ * If the Scala `Seq` was previously obtained from an implicit or explicit
+ * call of `asSeq(java.util.List)` then the original Java `List` will be
+ * returned.
+ *
+ * @param b The `Seq` to be converted.
+ * @return An object with an `asJava` method that returns a Java `List`
+ * view of the argument.
+ */
+ implicit def mutableSeqAsJavaListConverter[A](b : mutable.Seq[A]): AsJava[ju.List[A]] =
+ new AsJava(mutableSeqAsJavaList(b))
+
+ /**
+ * Adds an `asJava` method that implicitly converts a Scala `Seq` to a
+ * Java `List`.
+ *
+ * The returned Java `List` is backed by the provided Scala `Seq` and any
+ * side-effects of using it via the Java interface will be visible via the
+ * Scala interface and vice versa.
+ *
+ * If the Scala `Seq` was previously obtained from an implicit or explicit
+ * call of `asSeq(java.util.List)` then the original Java `List` will be
+ * returned.
+ *
+ * @param b The `Seq` to be converted.
+ * @return An object with an `asJava` method that returns a Java `List`
+ * view of the argument.
+ */
+ implicit def seqAsJavaListConverter[A](b : Seq[A]): AsJava[ju.List[A]] =
+ new AsJava(seqAsJavaList(b))
+
+ /**
+ * Adds an `asJava` method that implicitly converts a Scala mutable `Set`>
+ * to a Java `Set`.
+ *
+ * The returned Java `Set` is backed by the provided Scala `Set` and any
+ * side-effects of using it via the Java interface will be visible via
+ * the Scala interface and vice versa.
+ *
+ * If the Scala `Set` was previously obtained from an implicit or explicit
+ * call of `asSet(java.util.Set)` then the original Java `Set` will be
+ * returned.
+ *
+ * @param s The `Set` to be converted.
+ * @return An object with an `asJava` method that returns a Java `Set` view
+ * of the argument.
+ */
+ implicit def mutableSetAsJavaSetConverter[A](s : mutable.Set[A]): AsJava[ju.Set[A]] =
+ new AsJava(mutableSetAsJavaSet(s))
+
+ /**
+ * Adds an `asJava` method that implicitly converts a Scala `Set` to a
+ * Java `Set`.
+ *
+ * The returned Java `Set` is backed by the provided Scala `Set` and any
+ * side-effects of using it via the Java interface will be visible via
+ * the Scala interface and vice versa.
+ *
+ * If the Scala `Set` was previously obtained from an implicit or explicit
+ * call of `asSet(java.util.Set)` then the original Java `Set` will be
+ * returned.
+ *
+ * @param s The `Set` to be converted.
+ * @return An object with an `asJava` method that returns a Java `Set` view
+ * of the argument.
+ */
+ implicit def setAsJavaSetConverter[A](s : Set[A]): AsJava[ju.Set[A]] =
+ new AsJava(setAsJavaSet(s))
+
+ /**
+ * Adds an `asJava` method that implicitly converts a Scala mutable `Map`
+ * to a Java `Map`.
+ *
+ * The returned Java `Map` is backed by the provided Scala `Map` and any
+ * side-effects of using it via the Java interface will be visible via the
+ * Scala interface and vice versa.
+ *
+ * If the Scala `Map` was previously obtained from an implicit or explicit
+ * call of `asMap(java.util.Map)` then the original Java `Map` will be
+ * returned.
+ *
+ * @param m The `Map` to be converted.
+ * @return An object with an `asJava` method that returns a Java `Map` view
+ * of the argument.
+ */
+ implicit def mutableMapAsJavaMapConverter[A, B](m : mutable.Map[A, B]): AsJava[ju.Map[A, B]] =
+ new AsJava(mutableMapAsJavaMap(m))
+
+ /**
+ * Adds an `asJavaDictionary` method that implicitly converts a Scala
+ * mutable `Map` to a Java `Dictionary`.
+ *
+ * The returned Java `Dictionary` is backed by the provided Scala
+ * `Dictionary` and any side-effects of using it via the Java interface
+ * will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Dictionary` was previously obtained from an implicit or
+ * explicit call of `asMap(java.util.Dictionary)` then the original
+ * Java `Dictionary` will be returned.
+ *
+ * @param m The `Map` to be converted.
+ * @return An object with an `asJavaDictionary` method that returns a
+ * Java `Dictionary` view of the argument.
+ */
+ implicit def asJavaDictionaryConverter[A, B](m : mutable.Map[A, B]): AsJavaDictionary[A, B] =
+ new AsJavaDictionary(m)
+
+ /**
+ * Adds an `asJava` method that implicitly converts a Scala `Map` to
+ * a Java `Map`.
+ *
+ * The returned Java `Map` is backed by the provided Scala `Map` and any
+ * side-effects of using it via the Java interface will be visible via
+ * the Scala interface and vice versa.
+ *
+ * If the Scala `Map` was previously obtained from an implicit or explicit
+ * call of `asMap(java.util.Map)` then the original Java `Map` will be
+ * returned.
+ *
+ * @param m The `Map` to be converted.
+ * @return An object with an `asJava` method that returns a Java `Map` view
+ * of the argument.
+ */
+ implicit def mapAsJavaMapConverter[A, B](m : Map[A, B]): AsJava[ju.Map[A, B]] =
+ new AsJava(mapAsJavaMap(m))
+
+ /**
+ * Adds an `asJava` method that implicitly converts a Scala mutable
+ * `ConcurrentMap` to a Java `ConcurrentMap`.
+ *
+ * The returned Java `ConcurrentMap` is backed by the provided Scala
+ * `ConcurrentMap` and any side-effects of using it via the Java interface
+ * will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `ConcurrentMap` was previously obtained from an implicit or
+ * explicit call of `asConcurrentMap(java.util.concurrect.ConcurrentMap)`
+ * then the original Java `ConcurrentMap` will be returned.
+ *
+ * @param m The `ConcurrentMap` to be converted.
+ * @return An object with an `asJava` method that returns a Java
+ * `ConcurrentMap` view of the argument.
+ */
+ @deprecated("Use `concurrent.Map` instead of `ConcurrentMap`.", "2.10.0")
+ implicit def asJavaConcurrentMapConverter[A, B](m: mutable.ConcurrentMap[A, B]): AsJava[juc.ConcurrentMap[A, B]] =
+ new AsJava(asJavaConcurrentMap(m))
+
+ /**
+ * Adds an `asJava` method that implicitly converts a Scala mutable
+ * `concurrent.Map` to a Java `ConcurrentMap`.
+ *
+ * The returned Java `ConcurrentMap` is backed by the provided Scala
+ * `concurrent.Map` and any side-effects of using it via the Java interface
+ * will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `concurrent.Map` was previously obtained from an implicit or
+ * explicit call of `asConcurrentMap(java.util.concurrect.ConcurrentMap)`
+ * then the original Java `ConcurrentMap` will be returned.
+ *
+ * @param m The Scala `concurrent.Map` to be converted.
+ * @return An object with an `asJava` method that returns a Java
+ * `ConcurrentMap` view of the argument.
+ */
+ implicit def asJavaConcurrentMapConverter[A, B](m: concurrent.Map[A, B]): AsJava[juc.ConcurrentMap[A, B]] =
+ new AsJava(asJavaConcurrentMap(m))
+}
diff --git a/src/library/scala/collection/convert/DecorateAsScala.scala b/src/library/scala/collection/convert/DecorateAsScala.scala
new file mode 100644
index 0000000000..722f0b9af9
--- /dev/null
+++ b/src/library/scala/collection/convert/DecorateAsScala.scala
@@ -0,0 +1,208 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2011, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.collection
+package convert
+
+import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc }
+import Decorators._
+import WrapAsScala._
+
+trait DecorateAsScala {
+ /**
+ * Adds an `asScala` method that implicitly converts a Java `Iterator` to
+ * a Scala `Iterator`.
+ *
+ * The returned Scala `Iterator` is backed by the provided Java `Iterator`
+ * and any side-effects of using it via the Scala interface will be visible
+ * via the Java interface and vice versa.
+ *
+ * If the Java `Iterator` was previously obtained from an implicit or
+ * explicit call of `asIterator(scala.collection.Iterator)` then the
+ * original Scala `Iterator` will be returned.
+ *
+ * @param i The `Iterator` to be converted.
+ * @return An object with an `asScala` method that returns a Scala
+ * `Iterator` view of the argument.
+ */
+ implicit def asScalaIteratorConverter[A](i : ju.Iterator[A]): AsScala[Iterator[A]] =
+ new AsScala(asScalaIterator(i))
+
+ /**
+ * Adds an `asScala` method that implicitly converts a Java `Enumeration`
+ * to a Scala `Iterator`.
+ *
+ * The returned Scala `Iterator` is backed by the provided Java
+ * `Enumeration` and any side-effects of using it via the Scala interface
+ * will be visible via the Java interface and vice versa.
+ *
+ * If the Java `Enumeration` was previously obtained from an implicit or
+ * explicit call of `asEnumeration(scala.collection.Iterator)` then the
+ * original Scala `Iterator` will be returned.
+ *
+ * @param i The `Enumeration` to be converted.
+ * @return An object with an `asScala` method that returns a Scala
+ * `Iterator` view of the argument.
+ */
+ implicit def enumerationAsScalaIteratorConverter[A](i : ju.Enumeration[A]): AsScala[Iterator[A]] =
+ new AsScala(enumerationAsScalaIterator(i))
+
+ /**
+ * Adds an `asScala` method that implicitly converts a Java `Iterable` to
+ * a Scala `Iterable`.
+ *
+ * The returned Scala `Iterable` is backed by the provided Java `Iterable`
+ * and any side-effects of using it via the Scala interface will be visible
+ * via the Java interface and vice versa.
+ *
+ * If the Java `Iterable` was previously obtained from an implicit or
+ * explicit call of `asIterable(scala.collection.Iterable)` then the original
+ * Scala `Iterable` will be returned.
+ *
+ * @param i The `Iterable` to be converted.
+ * @return An object with an `asScala` method that returns a Scala `Iterable`
+ * view of the argument.
+ */
+ implicit def iterableAsScalaIterableConverter[A](i : jl.Iterable[A]): AsScala[Iterable[A]] =
+ new AsScala(iterableAsScalaIterable(i))
+
+ /**
+ * Adds an `asScala` method that implicitly converts a Java `Collection` to
+ * an Scala `Iterable`.
+ *
+ * If the Java `Collection` was previously obtained from an implicit or
+ * explicit call of `asCollection(scala.collection.SizedIterable)` then
+ * the original Scala `SizedIterable` will be returned.
+ *
+ * @param i The `Collection` to be converted.
+ * @return An object with an `asScala` method that returns a Scala
+ * `SizedIterable` view of the argument.
+ */
+ implicit def collectionAsScalaIterableConverter[A](i : ju.Collection[A]): AsScala[Iterable[A]] =
+ new AsScala(collectionAsScalaIterable(i))
+
+ /**
+ * Adds an `asScala` method that implicitly converts a Java `List` to a
+ * Scala mutable `Buffer`.
+ *
+ * The returned Scala `Buffer` is backed by the provided Java `List` and
+ * any side-effects of using it via the Scala interface will be visible via
+ * the Java interface and vice versa.
+ *
+ * If the Java `List` was previously obtained from an implicit or explicit
+ * call of `asList(scala.collection.mutable.Buffer)` then the original
+ * Scala `Buffer` will be returned.
+ *
+ * @param l The `List` to be converted.
+ * @return An object with an `asScala` method that returns a Scala mutable
+ * `Buffer` view of the argument.
+ */
+ implicit def asScalaBufferConverter[A](l : ju.List[A]): AsScala[mutable.Buffer[A]] =
+ new AsScala(asScalaBuffer(l))
+
+ /**
+ * Adds an `asScala` method that implicitly converts a Java `Set` to a
+ * Scala mutable `Set`.
+ *
+ * The returned Scala `Set` is backed by the provided Java `Set` and any
+ * side-effects of using it via the Scala interface will be visible via
+ * the Java interface and vice versa.
+ *
+ * If the Java `Set` was previously obtained from an implicit or explicit
+ * call of `asSet(scala.collection.mutable.Set)` then the original
+ * Scala `Set` will be returned.
+ *
+ * @param s The `Set` to be converted.
+ * @return An object with an `asScala` method that returns a Scala mutable
+ * `Set` view of the argument.
+ */
+ implicit def asScalaSetConverter[A](s : ju.Set[A]): AsScala[mutable.Set[A]] =
+ new AsScala(asScalaSet(s))
+
+ /**
+ * Adds an `asScala` method that implicitly converts a Java `Map` to a Scala
+ * mutable `Map`. The returned Scala `Map` is backed by the provided Java
+ * `Map` and any side-effects of using it via the Scala interface will
+ * be visible via the Java interface and vice versa.
+ *
+ * If the Java `Map` was previously obtained from an implicit or explicit
+ * call of `asMap(scala.collection.mutable.Map)` then the original
+ * Scala `Map` will be returned.
+ *
+ * @param m The `Map` to be converted.
+ * @return An object with an `asScala` method that returns a Scala mutable
+ * `Map` view of the argument.
+ */
+ implicit def mapAsScalaMapConverter[A, B](m : ju.Map[A, B]): AsScala[mutable.Map[A, B]] =
+ new AsScala(mapAsScalaMap(m))
+
+ /**
+ * Adds an `asScala` method that implicitly converts a Java `ConcurrentMap`
+ * to a Scala mutable `ConcurrentMap`. The returned Scala `ConcurrentMap` is
+ * backed by the provided Java `ConcurrentMap` and any side-effects of using
+ * it via the Scala interface will be visible via the Java interface and
+ * vice versa.
+ *
+ * If the Java `ConcurrentMap` was previously obtained from an implicit or
+ * explicit call of `asConcurrentMap(scala.collection.mutable.ConcurrentMap)`
+ * then the original Scala `ConcurrentMap` will be returned.
+ *
+ * @param m The `ConcurrentMap` to be converted.
+ * @return An object with an `asScala` method that returns a Scala mutable
+ * `ConcurrentMap` view of the argument.
+ */
+ @deprecated("Use `mapAsScalaConcurrentMapConverter` instead, and use `concurrent.Map` instead of `ConcurrentMap`.", "2.10.0")
+ def asScalaConcurrentMapConverter[A, B](m: juc.ConcurrentMap[A, B]): AsScala[mutable.ConcurrentMap[A, B]] =
+ new AsScala(asScalaConcurrentMap(m))
+
+ /**
+ * Adds an `asScala` method that implicitly converts a Java `ConcurrentMap`
+ * to a Scala mutable `concurrent.Map`. The returned Scala `concurrent.Map` is
+ * backed by the provided Java `ConcurrentMap` and any side-effects of using
+ * it via the Scala interface will be visible via the Java interface and
+ * vice versa.
+ *
+ * If the Java `ConcurrentMap` was previously obtained from an implicit or
+ * explicit call of `mapAsScalaConcurrentMap(scala.collection.mutable.ConcurrentMap)`
+ * then the original Scala `concurrent.Map` will be returned.
+ *
+ * @param m The `ConcurrentMap` to be converted.
+ * @return An object with an `asScala` method that returns a Scala mutable
+ * `concurrent.Map` view of the argument.
+ */
+ implicit def mapAsScalaConcurrentMapConverter[A, B](m: juc.ConcurrentMap[A, B]): AsScala[concurrent.Map[A, B]] =
+ new AsScala(mapAsScalaConcurrentMap(m))
+
+ /**
+ * Adds an `asScala` method that implicitly converts a Java `Dictionary`
+ * to a Scala mutable `Map[String, String]`. The returned Scala
+ * `Map[String, String]` is backed by the provided Java `Dictionary` and
+ * any side-effects of using it via the Scala interface will be visible via
+ * the Java interface and vice versa.
+ *
+ * @param m The `Dictionary` to be converted.
+ * @return An object with an `asScala` method that returns a Scala mutable
+ * `Map[String, String]` view of the argument.
+ */
+ implicit def dictionaryAsScalaMapConverter[A, B](p: ju.Dictionary[A, B]): AsScala[mutable.Map[A, B]] =
+ new AsScala(dictionaryAsScalaMap(p))
+
+ /**
+ * Adds an `asScala` method that implicitly converts a Java `Properties`
+ * to a Scala mutable `Map[String, String]`. The returned Scala
+ * `Map[String, String]` is backed by the provided Java `Properties` and
+ * any side-effects of using it via the Scala interface will be visible via
+ * the Java interface and vice versa.
+ *
+ * @param m The `Properties` to be converted.
+ * @return An object with an `asScala` method that returns a Scala mutable
+ * `Map[String, String]` view of the argument.
+ */
+ implicit def propertiesAsScalaMapConverter(p: ju.Properties): AsScala[mutable.Map[String, String]] =
+ new AsScala(propertiesAsScalaMap(p))
+}
diff --git a/src/library/scala/collection/convert/Decorators.scala b/src/library/scala/collection/convert/Decorators.scala
new file mode 100644
index 0000000000..3bdd9a0f1c
--- /dev/null
+++ b/src/library/scala/collection/convert/Decorators.scala
@@ -0,0 +1,46 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2011, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.collection
+package convert
+
+import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc }
+
+private[collection] trait Decorators {
+ /** Generic class containing the `asJava` converter method */
+ class AsJava[A](op: => A) {
+ /** Converts a Scala collection to the corresponding Java collection */
+ def asJava: A = op
+ }
+
+ /** Generic class containing the `asScala` converter method */
+ class AsScala[A](op: => A) {
+ /** Converts a Java collection to the corresponding Scala collection */
+ def asScala: A = op
+ }
+
+ /** Generic class containing the `asJavaCollection` converter method */
+ class AsJavaCollection[A](i: Iterable[A]) {
+ /** Converts a Scala `Iterable` to a Java `Collection` */
+ def asJavaCollection: ju.Collection[A] = JavaConversions.asJavaCollection(i)
+ }
+
+ /** Generic class containing the `asJavaEnumeration` converter method */
+ class AsJavaEnumeration[A](i: Iterator[A]) {
+ /** Converts a Scala `Iterator` to a Java `Enumeration` */
+ def asJavaEnumeration: ju.Enumeration[A] = JavaConversions.asJavaEnumeration(i)
+ }
+
+ /** Generic class containing the `asJavaDictionary` converter method */
+ class AsJavaDictionary[A, B](m : mutable.Map[A, B]) {
+ /** Converts a Scala `Map` to a Java `Dictionary` */
+ def asJavaDictionary: ju.Dictionary[A, B] = JavaConversions.asJavaDictionary(m)
+ }
+}
+
+private[collection] object Decorators extends Decorators
diff --git a/src/library/scala/collection/convert/WrapAsJava.scala b/src/library/scala/collection/convert/WrapAsJava.scala
new file mode 100644
index 0000000000..cdec72b9fe
--- /dev/null
+++ b/src/library/scala/collection/convert/WrapAsJava.scala
@@ -0,0 +1,285 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2011, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.collection
+package convert
+
+import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc }
+import Wrappers._
+
+trait WrapAsJava {
+ /**
+ * Implicitly converts a Scala Iterator to a Java Iterator.
+ * The returned Java Iterator is backed by the provided Scala
+ * Iterator and any side-effects of using it via the Java interface will
+ * be visible via the Scala interface and vice versa.
+ *
+ * If the Scala Iterator was previously obtained from an implicit or
+ * explicit call of `asIterator(java.util.Iterator)` then the original
+ * Java Iterator will be returned.
+ *
+ * @param i The Iterator to be converted.
+ * @return A Java Iterator view of the argument.
+ */
+ implicit def asJavaIterator[A](it: Iterator[A]): ju.Iterator[A] = it match {
+ case JIteratorWrapper(wrapped) => wrapped.asInstanceOf[ju.Iterator[A]]
+ case _ => IteratorWrapper(it)
+ }
+
+ /**
+ * Implicitly converts a Scala Iterator to a Java Enumeration.
+ * The returned Java Enumeration is backed by the provided Scala
+ * Iterator and any side-effects of using it via the Java interface will
+ * be visible via the Scala interface and vice versa.
+ *
+ * If the Scala Iterator was previously obtained from an implicit or
+ * explicit call of `asIterator(java.util.Enumeration)` then the
+ * original Java Enumeration will be returned.
+ *
+ * @param i The Iterator to be converted.
+ * @return A Java Enumeration view of the argument.
+ */
+ implicit def asJavaEnumeration[A](it: Iterator[A]): ju.Enumeration[A] = it match {
+ case JEnumerationWrapper(wrapped) => wrapped.asInstanceOf[ju.Enumeration[A]]
+ case _ => IteratorWrapper(it)
+ }
+
+ /**
+ * Implicitly converts a Scala Iterable to a Java Iterable.
+ * The returned Java Iterable is backed by the provided Scala
+ * Iterable and any side-effects of using it via the Java interface will
+ * be visible via the Scala interface and vice versa.
+ *
+ * If the Scala Iterable was previously obtained from an implicit or
+ * explicit call of `asIterable(java.lang.Iterable)` then the original
+ * Java Iterable will be returned.
+ *
+ * @param i The Iterable to be converted.
+ * @return A Java Iterable view of the argument.
+ */
+ implicit def asJavaIterable[A](i: Iterable[A]): jl.Iterable[A] = i match {
+ case JIterableWrapper(wrapped) => wrapped.asInstanceOf[jl.Iterable[A]]
+ case _ => IterableWrapper(i)
+ }
+
+ /**
+ * Implicitly converts a Scala Iterable to an immutable Java
+ * Collection.
+ *
+ * If the Scala Iterable was previously obtained from an implicit or
+ * explicit call of `asSizedIterable(java.util.Collection)` then the original
+ * Java Collection will be returned.
+ *
+ * @param i The SizedIterable to be converted.
+ * @return A Java Collection view of the argument.
+ */
+ implicit def asJavaCollection[A](it: Iterable[A]): ju.Collection[A] = it match {
+ case JCollectionWrapper(wrapped) => wrapped.asInstanceOf[ju.Collection[A]]
+ case _ => new IterableWrapper(it)
+ }
+
+ /**
+ * Implicitly converts a Scala mutable Buffer to a Java List.
+ * The returned Java List is backed by the provided Scala
+ * Buffer and any side-effects of using it via the Java interface will
+ * be visible via the Scala interface and vice versa.
+ *
+ * If the Scala Buffer was previously obtained from an implicit or
+ * explicit call of `asBuffer(java.util.List)` then the original
+ * Java List will be returned.
+ *
+ * @param b The Buffer to be converted.
+ * @return A Java List view of the argument.
+ */
+ implicit def bufferAsJavaList[A](b: mutable.Buffer[A]): ju.List[A] = b match {
+ case JListWrapper(wrapped) => wrapped
+ case _ => new MutableBufferWrapper(b)
+ }
+
+ /**
+ * Implicitly converts a Scala mutable Seq to a Java List.
+ * The returned Java List is backed by the provided Scala
+ * Seq and any side-effects of using it via the Java interface will
+ * be visible via the Scala interface and vice versa.
+ *
+ * If the Scala Seq was previously obtained from an implicit or
+ * explicit call of `asSeq(java.util.List)` then the original
+ * Java List will be returned.
+ *
+ * @param b The Seq to be converted.
+ * @return A Java List view of the argument.
+ */
+ implicit def mutableSeqAsJavaList[A](seq: mutable.Seq[A]): ju.List[A] = seq match {
+ case JListWrapper(wrapped) => wrapped
+ case _ => new MutableSeqWrapper(seq)
+ }
+
+ /**
+ * Implicitly converts a Scala Seq to a Java List.
+ * The returned Java List is backed by the provided Scala
+ * Seq and any side-effects of using it via the Java interface will
+ * be visible via the Scala interface and vice versa.
+ *
+ * If the Scala Seq was previously obtained from an implicit or
+ * explicit call of `asSeq(java.util.List)` then the original
+ * Java List will be returned.
+ *
+ * @param b The Seq to be converted.
+ * @return A Java List view of the argument.
+ */
+ implicit def seqAsJavaList[A](seq: Seq[A]): ju.List[A] = seq match {
+ case JListWrapper(wrapped) => wrapped.asInstanceOf[ju.List[A]]
+ case _ => new SeqWrapper(seq)
+ }
+
+ /**
+ * Implicitly converts a Scala mutable Set to a Java Set.
+ * The returned Java Set is backed by the provided Scala
+ * Set and any side-effects of using it via the Java interface will
+ * be visible via the Scala interface and vice versa.
+ *
+ * If the Scala Set was previously obtained from an implicit or
+ * explicit call of `asSet(java.util.Set)` then the original
+ * Java Set will be returned.
+ *
+ * @param s The Set to be converted.
+ * @return A Java Set view of the argument.
+ */
+ implicit def mutableSetAsJavaSet[A](s: mutable.Set[A]): ju.Set[A] = s match {
+ case JSetWrapper(wrapped) => wrapped
+ case _ => new MutableSetWrapper(s)
+ }
+
+ /**
+ * Implicitly converts a Scala Set to a Java Set.
+ * The returned Java Set is backed by the provided Scala
+ * Set and any side-effects of using it via the Java interface will
+ * be visible via the Scala interface and vice versa.
+ *
+ * If the Scala Set was previously obtained from an implicit or
+ * explicit call of asSet(java.util.Set) then the original
+ * Java Set will be returned.
+ *
+ * @param s The Set to be converted.
+ * @return A Java Set view of the argument.
+ */
+ implicit def setAsJavaSet[A](s: Set[A]): ju.Set[A] = s match {
+ case JSetWrapper(wrapped) => wrapped
+ case _ => new SetWrapper(s)
+ }
+
+ /**
+ * Implicitly converts a Scala mutable Map to a Java Map.
+ * The returned Java Map is backed by the provided Scala
+ * Map and any side-effects of using it via the Java interface will
+ * be visible via the Scala interface and vice versa.
+ *
+ * If the Scala Map was previously obtained from an implicit or
+ * explicit call of `asMap(java.util.Map)` then the original
+ * Java Map will be returned.
+ *
+ * @param m The Map to be converted.
+ * @return A Java Map view of the argument.
+ */
+ implicit def mutableMapAsJavaMap[A, B](m: mutable.Map[A, B]): ju.Map[A, B] = m match {
+ //case JConcurrentMapWrapper(wrapped) => wrapped
+ case JMapWrapper(wrapped) => wrapped
+ case _ => new MutableMapWrapper(m)
+ }
+
+ /**
+ * Implicitly converts a Scala mutable `Map` to a Java `Dictionary`.
+ *
+ * The returned Java `Dictionary` is backed by the provided Scala
+ * `Dictionary` and any side-effects of using it via the Java interface
+ * will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Dictionary` was previously obtained from an implicit or
+ * explicit call of `asMap(java.util.Dictionary)` then the original
+ * Java Dictionary will be returned.
+ *
+ * @param m The `Map` to be converted.
+ * @return A Java `Dictionary` view of the argument.
+ */
+ implicit def asJavaDictionary[A, B](m: mutable.Map[A, B]): ju.Dictionary[A, B] = m match {
+ //case JConcurrentMapWrapper(wrapped) => wrapped
+ case JDictionaryWrapper(wrapped) => wrapped
+ case _ => new DictionaryWrapper(m)
+ }
+
+ /**
+ * Implicitly converts a Scala `Map` to a Java `Map`.
+ *
+ * The returned Java `Map` is backed by the provided Scala `Map` and
+ * any side-effects of using it via the Java interface will be visible
+ * via the Scala interface and vice versa.
+ *
+ * If the Scala `Map` was previously obtained from an implicit or
+ * explicit call of `asMap(java.util.Map)` then the original
+ * Java `Map` will be returned.
+ *
+ * @param m The `Map` to be converted.
+ * @return A Java `Map` view of the argument.
+ */
+ implicit def mapAsJavaMap[A, B](m: Map[A, B]): ju.Map[A, B] = m match {
+ //case JConcurrentMapWrapper(wrapped) => wrapped
+ case JMapWrapper(wrapped) => wrapped.asInstanceOf[ju.Map[A, B]]
+ case _ => new MapWrapper(m)
+ }
+
+ /**
+ * Implicitly converts a Scala mutable `ConcurrentMap` to a Java
+ * `ConcurrentMap`.
+ *
+ * The returned Java `ConcurrentMap` is backed by the provided Scala
+ * `ConcurrentMap` and any side-effects of using it via the Java interface
+ * will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `ConcurrentMap` was previously obtained from an implicit or
+ * explicit call of `asScalaConcurrentMap(java.util.concurrect.ConcurrentMap)`
+ * then the original Java ConcurrentMap will be returned.
+ *
+ * @param m The `ConcurrentMap` to be converted.
+ * @return A Java `ConcurrentMap` view of the argument.
+ */
+ @deprecated("Use `concurrent.Map` instead of `ConcurrentMap`.", "2.10.0")
+ implicit def asJavaConcurrentMap[A, B](m: mutable.ConcurrentMap[A, B]): juc.ConcurrentMap[A, B] = m match {
+ case JConcurrentMapDeprecatedWrapper(wrapped) => wrapped
+ case _ => new ConcurrentMapDeprecatedWrapper(m)
+ }
+
+ /**
+ * Implicitly converts a Scala mutable `concurrent.Map` to a Java
+ * `ConcurrentMap`.
+ *
+ * The returned Java `ConcurrentMap` is backed by the provided Scala
+ * `concurrent.Map` and any side-effects of using it via the Java interface
+ * will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `concurrent.Map` was previously obtained from an implicit or
+ * explicit call of `mapAsScalaConcurrentMap(java.util.concurrect.ConcurrentMap)`
+ * then the original Java ConcurrentMap will be returned.
+ *
+ * @param m The Scala `concurrent.Map` to be converted.
+ * @return A Java `ConcurrentMap` view of the argument.
+ */
+ implicit def asJavaConcurrentMap[A, B](m: concurrent.Map[A, B]): juc.ConcurrentMap[A, B] = m match {
+ case JConcurrentMapWrapper(wrapped) => wrapped
+ case _ => new ConcurrentMapWrapper(m)
+ }
+}
+
+object WrapAsJava extends WrapAsJava { }
+
+
+
+
+
+
+
+
diff --git a/src/library/scala/collection/convert/WrapAsScala.scala b/src/library/scala/collection/convert/WrapAsScala.scala
new file mode 100644
index 0000000000..56e13b2105
--- /dev/null
+++ b/src/library/scala/collection/convert/WrapAsScala.scala
@@ -0,0 +1,212 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2011, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.collection
+package convert
+
+import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc }
+import Wrappers._
+
+trait WrapAsScala {
+ /**
+ * Implicitly converts a Java `Iterator` to a Scala `Iterator`.
+ *
+ * The returned Scala `Iterator` is backed by the provided Java `Iterator`
+ * and any side-effects of using it via the Scala interface will be visible
+ * via the Java interface and vice versa.
+ *
+ * If the Java `Iterator` was previously obtained from an implicit or
+ * explicit call of `asIterator(scala.collection.Iterator)` then the
+ * original Scala `Iterator` will be returned.
+ *
+ * @param i The `Iterator` to be converted.
+ * @return A Scala `Iterator` view of the argument.
+ */
+ implicit def asScalaIterator[A](it: ju.Iterator[A]): Iterator[A] = it match {
+ case IteratorWrapper(wrapped) => wrapped
+ case _ => JIteratorWrapper(it)
+ }
+
+ /**
+ * Implicitly converts a Java Enumeration to a Scala Iterator.
+ * The returned Scala Iterator is backed by the provided Java
+ * Enumeration and any side-effects of using it via the Scala interface will
+ * be visible via the Java interface and vice versa.
+ *
+ * If the Java Enumeration was previously obtained from an implicit or
+ * explicit call of `enumerationAsScalaIterator(scala.collection.Iterator)`
+ * then the original Scala Iterator will be returned.
+ *
+ * @param i The Enumeration to be converted.
+ * @return A Scala Iterator view of the argument.
+ */
+ implicit def enumerationAsScalaIterator[A](i: ju.Enumeration[A]): Iterator[A] = i match {
+ case IteratorWrapper(wrapped) => wrapped
+ case _ => JEnumerationWrapper(i)
+ }
+
+ /**
+ * Implicitly converts a Java `Iterable` to a Scala `Iterable`.
+ *
+ * The returned Scala `Iterable` is backed by the provided Java `Iterable`
+ * and any side-effects of using it via the Scala interface will be visible
+ * via the Java interface and vice versa.
+ *
+ * If the Java `Iterable` was previously obtained from an implicit or
+ * explicit call of `iterableAsScalaIterable(scala.collection.Iterable)`
+ * then the original Scala Iterable will be returned.
+ *
+ * @param i The Iterable to be converted.
+ * @return A Scala Iterable view of the argument.
+ */
+ implicit def iterableAsScalaIterable[A](i: jl.Iterable[A]): Iterable[A] = i match {
+ case IterableWrapper(wrapped) => wrapped
+ case _ => JIterableWrapper(i)
+ }
+
+ /**
+ * Implicitly converts a Java `Collection` to an Scala `Iterable`.
+ *
+ * If the Java `Collection` was previously obtained from an implicit or
+ * explicit call of `collectionAsScalaIterable(scala.collection.SizedIterable)`
+ * then the original Scala `Iterable` will be returned.
+ *
+ * @param i The Collection to be converted.
+ * @return A Scala Iterable view of the argument.
+ */
+ implicit def collectionAsScalaIterable[A](i: ju.Collection[A]): Iterable[A] = i match {
+ case IterableWrapper(wrapped) => wrapped
+ case _ => JCollectionWrapper(i)
+ }
+
+ /**
+ * Implicitly converts a Java `List` to a Scala mutable `Buffer`.
+ *
+ * The returned Scala `Buffer` is backed by the provided Java `List`
+ * and any side-effects of using it via the Scala interface will
+ * be visible via the Java interface and vice versa.
+ *
+ * If the Java `List` was previously obtained from an implicit or
+ * explicit call of `asScalaBuffer(scala.collection.mutable.Buffer)`
+ * then the original Scala `Buffer` will be returned.
+ *
+ * @param l The `List` to be converted.
+ * @return A Scala mutable `Buffer` view of the argument.
+ */
+ implicit def asScalaBuffer[A](l: ju.List[A]): mutable.Buffer[A] = l match {
+ case MutableBufferWrapper(wrapped) => wrapped
+ case _ =>new JListWrapper(l)
+ }
+
+ /**
+ * Implicitly converts a Java Set to a Scala mutable Set.
+ * The returned Scala Set is backed by the provided Java
+ * Set and any side-effects of using it via the Scala interface will
+ * be visible via the Java interface and vice versa.
+ *
+ * If the Java Set was previously obtained from an implicit or
+ * explicit call of `asScalaSet(scala.collection.mutable.Set)` then
+ * the original Scala Set will be returned.
+ *
+ * @param s The Set to be converted.
+ * @return A Scala mutable Set view of the argument.
+ */
+ implicit def asScalaSet[A](s: ju.Set[A]): mutable.Set[A] = s match {
+ case MutableSetWrapper(wrapped) => wrapped
+ case _ =>new JSetWrapper(s)
+ }
+
+ /**
+ * Implicitly converts a Java `Map` to a Scala mutable `Map`.
+ *
+ * The returned Scala `Map` is backed by the provided Java `Map` and any
+ * side-effects of using it via the Scala interface will be visible via
+ * the Java interface and vice versa.
+ *
+ * If the Java `Map` was previously obtained from an implicit or
+ * explicit call of `mapAsScalaMap(scala.collection.mutable.Map)` then
+ * the original Scala Map will be returned.
+ *
+ * @param m The Map to be converted.
+ * @return A Scala mutable Map view of the argument.
+ */
+ implicit def mapAsScalaMap[A, B](m: ju.Map[A, B]): mutable.Map[A, B] = m match {
+ //case ConcurrentMapWrapper(wrapped) => wrapped
+ case MutableMapWrapper(wrapped) => wrapped
+ case _ => new JMapWrapper(m)
+ }
+
+ /**
+ * Implicitly converts a Java ConcurrentMap to a Scala mutable ConcurrentMap.
+ * The returned Scala ConcurrentMap is backed by the provided Java
+ * ConcurrentMap and any side-effects of using it via the Scala interface will
+ * be visible via the Java interface and vice versa.
+ *
+ * If the Java ConcurrentMap was previously obtained from an implicit or
+ * explicit call of `asConcurrentMap(scala.collection.mutable.ConcurrentMap)`
+ * then the original Scala ConcurrentMap will be returned.
+ *
+ * @param m The ConcurrentMap to be converted.
+ * @return A Scala mutable ConcurrentMap view of the argument.
+ */
+ @deprecated("Use `mapAsScalaConcurrentMap` instead, and use `concurrent.Map` instead of `ConcurrentMap`.", "2.10.0")
+ def asScalaConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): mutable.ConcurrentMap[A, B] = m match {
+ case cmw: ConcurrentMapDeprecatedWrapper[a, b] => cmw.underlying
+ case _ => new JConcurrentMapDeprecatedWrapper(m)
+ }
+
+ /**
+ * Implicitly converts a Java ConcurrentMap to a Scala mutable ConcurrentMap.
+ * The returned Scala ConcurrentMap is backed by the provided Java
+ * ConcurrentMap and any side-effects of using it via the Scala interface will
+ * be visible via the Java interface and vice versa.
+ *
+ * If the Java ConcurrentMap was previously obtained from an implicit or
+ * explicit call of `asConcurrentMap(scala.collection.mutable.ConcurrentMap)`
+ * then the original Scala ConcurrentMap will be returned.
+ *
+ * @param m The ConcurrentMap to be converted.
+ * @return A Scala mutable ConcurrentMap view of the argument.
+ */
+ implicit def mapAsScalaConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): concurrent.Map[A, B] = m match {
+ case cmw: ConcurrentMapWrapper[a, b] => cmw.underlying
+ case _ => new JConcurrentMapWrapper(m)
+ }
+
+ /**
+ * Implicitly converts a Java `Dictionary` to a Scala mutable
+ * `Map[String, String]`.
+ *
+ * The returned Scala `Map[String, String]` is backed by the provided Java
+ * `Dictionary` and any side-effects of using it via the Scala interface
+ * will be visible via the Java interface and vice versa.
+ *
+ * @param m The Dictionary to be converted.
+ * @return A Scala mutable Map[String, String] view of the argument.
+ */
+ implicit def dictionaryAsScalaMap[A, B](p: ju.Dictionary[A, B]): mutable.Map[A, B] = p match {
+ case DictionaryWrapper(wrapped) => wrapped
+ case _ => new JDictionaryWrapper(p)
+ }
+
+ /**
+ * Implicitly converts a Java `Properties` to a Scala `mutable Map[String, String]`.
+ *
+ * The returned Scala `Map[String, String]` is backed by the provided Java
+ * `Properties` and any side-effects of using it via the Scala interface
+ * will be visible via the Java interface and vice versa.
+ *
+ * @param m The Properties to be converted.
+ * @return A Scala mutable Map[String, String] view of the argument.
+ */
+ implicit def propertiesAsScalaMap(p: ju.Properties): mutable.Map[String, String] = p match {
+ case _ => new JPropertiesWrapper(p)
+ }
+}
+
+object WrapAsScala extends WrapAsScala { }
diff --git a/src/library/scala/collection/convert/Wrappers.scala b/src/library/scala/collection/convert/Wrappers.scala
new file mode 100644
index 0000000000..b1b48b760f
--- /dev/null
+++ b/src/library/scala/collection/convert/Wrappers.scala
@@ -0,0 +1,469 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2011, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.collection
+package convert
+
+import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc }
+import WrapAsScala._
+import WrapAsJava._
+
+/** Don't put the implementations in the same scope as the implicits
+ * which utilize them, or they will stow away into every scope which
+ * extends one of those implementations. See SI-5580.
+ */
+private[collection] trait Wrappers {
+ trait IterableWrapperTrait[A] extends ju.AbstractCollection[A] {
+ val underlying: Iterable[A]
+ def size = underlying.size
+ override def iterator = IteratorWrapper(underlying.iterator)
+ override def isEmpty = underlying.isEmpty
+ }
+
+ case class IteratorWrapper[A](underlying: Iterator[A]) extends ju.Iterator[A] with ju.Enumeration[A] {
+ def hasNext = underlying.hasNext
+ def next() = underlying.next
+ def hasMoreElements = underlying.hasNext
+ def nextElement() = underlying.next
+ def remove() = throw new UnsupportedOperationException
+ }
+
+ class ToIteratorWrapper[A](underlying : Iterator[A]) {
+ def asJava = new IteratorWrapper(underlying)
+ }
+
+ case class JIteratorWrapper[A](underlying: ju.Iterator[A]) extends AbstractIterator[A] with Iterator[A] {
+ def hasNext = underlying.hasNext
+ def next() = underlying.next
+ }
+
+ case class JEnumerationWrapper[A](underlying: ju.Enumeration[A]) extends AbstractIterator[A] with Iterator[A] {
+ def hasNext = underlying.hasMoreElements
+ def next() = underlying.nextElement
+ }
+
+ case class IterableWrapper[A](underlying: Iterable[A]) extends ju.AbstractCollection[A] with IterableWrapperTrait[A] { }
+
+ case class JIterableWrapper[A](underlying: jl.Iterable[A]) extends AbstractIterable[A] with Iterable[A] {
+ def iterator = underlying.iterator
+ def newBuilder[B] = new mutable.ArrayBuffer[B]
+ }
+
+ case class JCollectionWrapper[A](underlying: ju.Collection[A]) extends AbstractIterable[A] with Iterable[A] {
+ def iterator = underlying.iterator
+ override def size = underlying.size
+ override def isEmpty = underlying.isEmpty
+ def newBuilder[B] = new mutable.ArrayBuffer[B]
+ }
+
+ case class SeqWrapper[A](underlying: Seq[A]) extends ju.AbstractList[A] with IterableWrapperTrait[A] {
+ def get(i: Int) = underlying(i)
+ }
+
+ case class MutableSeqWrapper[A](underlying: mutable.Seq[A]) extends ju.AbstractList[A] with IterableWrapperTrait[A] {
+ def get(i: Int) = underlying(i)
+ override def set(i: Int, elem: A) = {
+ val p = underlying(i)
+ underlying(i) = elem
+ p
+ }
+ }
+
+ case class MutableBufferWrapper[A](underlying: mutable.Buffer[A]) extends ju.AbstractList[A] with IterableWrapperTrait[A] {
+ def get(i: Int) = underlying(i)
+ override def set(i: Int, elem: A) = { val p = underlying(i); underlying(i) = elem; p }
+ override def add(elem: A) = { underlying append elem; true }
+ override def remove(i: Int) = underlying remove i
+ }
+
+ case class JListWrapper[A](val underlying: ju.List[A]) extends mutable.AbstractBuffer[A] with mutable.Buffer[A] {
+ def length = underlying.size
+ override def isEmpty = underlying.isEmpty
+ override def iterator: Iterator[A] = underlying.iterator
+ def apply(i: Int) = underlying.get(i)
+ def update(i: Int, elem: A) = underlying.set(i, elem)
+ def +=:(elem: A) = { underlying.subList(0, 0) add elem; this }
+ def +=(elem: A): this.type = { underlying add elem; this }
+ def insertAll(i: Int, elems: Traversable[A]) = {
+ val ins = underlying.subList(0, i)
+ elems.seq.foreach(ins.add(_))
+ }
+ def remove(i: Int) = underlying.remove(i)
+ def clear() = underlying.clear()
+ def result = this
+ }
+
+ class SetWrapper[A](underlying: Set[A]) extends ju.AbstractSet[A] {
+ self =>
+ def size = underlying.size
+ def iterator = new ju.Iterator[A] {
+ val ui = underlying.iterator
+ var prev: Option[A] = None
+ def hasNext = ui.hasNext
+ def next = { val e = ui.next; prev = Some(e); e }
+ def remove = prev match {
+ case Some(e) =>
+ underlying match {
+ case ms: mutable.Set[a] =>
+ ms remove e
+ prev = None
+ case _ =>
+ throw new UnsupportedOperationException("remove")
+ }
+ case _ =>
+ throw new IllegalStateException("next must be called at least once before remove")
+ }
+ }
+ }
+
+ case class MutableSetWrapper[A](underlying: mutable.Set[A]) extends SetWrapper[A](underlying) {
+ override def add(elem: A) = {
+ val sz = underlying.size
+ underlying += elem
+ sz < underlying.size
+ }
+ override def remove(elem: AnyRef) =
+ try underlying remove elem.asInstanceOf[A]
+ catch { case ex: ClassCastException => false }
+ override def clear() = underlying.clear()
+ }
+
+ case class JSetWrapper[A](underlying: ju.Set[A]) extends mutable.AbstractSet[A] with mutable.Set[A] with mutable.SetLike[A, JSetWrapper[A]] {
+
+ override def size = underlying.size
+
+ def iterator = underlying.iterator
+
+ def contains(elem: A): Boolean = underlying.contains(elem)
+
+ def +=(elem: A): this.type = { underlying add elem; this }
+ def -=(elem: A): this.type = { underlying remove elem; this }
+
+ override def add(elem: A): Boolean = underlying add elem
+ override def remove(elem: A): Boolean = underlying remove elem
+ override def clear() = underlying.clear()
+
+ override def empty = JSetWrapper(new ju.HashSet[A])
+ }
+
+ class MapWrapper[A, B](underlying: Map[A, B]) extends ju.AbstractMap[A, B] { self =>
+ override def size = underlying.size
+
+ override def get(key: AnyRef): B = try {
+ underlying get key.asInstanceOf[A] match {
+ case None => null.asInstanceOf[B]
+ case Some(v) => v
+ }
+ } catch {
+ case ex: ClassCastException => null.asInstanceOf[B]
+ }
+
+ override def entrySet: ju.Set[ju.Map.Entry[A, B]] = new ju.AbstractSet[ju.Map.Entry[A, B]] {
+ def size = self.size
+
+ def iterator = new ju.Iterator[ju.Map.Entry[A, B]] {
+ val ui = underlying.iterator
+ var prev : Option[A] = None
+
+ def hasNext = ui.hasNext
+
+ def next() = {
+ val (k, v) = ui.next
+ prev = Some(k)
+ new ju.Map.Entry[A, B] {
+ def getKey = k
+ def getValue = v
+ def setValue(v1 : B) = self.put(k, v1)
+ override def hashCode = k.hashCode + v.hashCode
+ override def equals(other: Any) = other match {
+ case e: ju.Map.Entry[_, _] => k == e.getKey && v == e.getValue
+ case _ => false
+ }
+ }
+ }
+
+ def remove() {
+ prev match {
+ case Some(k) =>
+ underlying match {
+ case mm: mutable.Map[a, _] =>
+ mm remove k
+ prev = None
+ case _ =>
+ throw new UnsupportedOperationException("remove")
+ }
+ case _ =>
+ throw new IllegalStateException("next must be called at least once before remove")
+ }
+ }
+ }
+ }
+ }
+
+ case class MutableMapWrapper[A, B](underlying: mutable.Map[A, B]) extends MapWrapper[A, B](underlying) {
+ override def put(k: A, v: B) = underlying.put(k, v) match {
+ case Some(v1) => v1
+ case None => null.asInstanceOf[B]
+ }
+
+ override def remove(k: AnyRef): B = try {
+ underlying remove k.asInstanceOf[A] match {
+ case None => null.asInstanceOf[B]
+ case Some(v) => v
+ }
+ } catch {
+ case ex: ClassCastException => null.asInstanceOf[B]
+ }
+
+ override def clear() = underlying.clear()
+ }
+
+ trait JMapWrapperLike[A, B, +Repr <: mutable.MapLike[A, B, Repr] with mutable.Map[A, B]] extends mutable.Map[A, B] with mutable.MapLike[A, B, Repr] {
+ def underlying: ju.Map[A, B]
+
+ override def size = underlying.size
+
+ def get(k: A) = {
+ val v = underlying get k
+ if (v != null)
+ Some(v)
+ else if (underlying containsKey k)
+ Some(null.asInstanceOf[B])
+ else
+ None
+ }
+
+ def +=(kv: (A, B)): this.type = { underlying.put(kv._1, kv._2); this }
+ def -=(key: A): this.type = { underlying remove key; this }
+
+ override def put(k: A, v: B): Option[B] = {
+ val r = underlying.put(k, v)
+ if (r != null) Some(r) else None
+ }
+
+ override def update(k: A, v: B) { underlying.put(k, v) }
+
+ override def remove(k: A): Option[B] = {
+ val r = underlying remove k
+ if (r != null) Some(r) else None
+ }
+
+ def iterator: Iterator[(A, B)] = new AbstractIterator[(A, B)] {
+ val ui = underlying.entrySet.iterator
+ def hasNext = ui.hasNext
+ def next() = { val e = ui.next(); (e.getKey, e.getValue) }
+ }
+
+ override def clear() = underlying.clear()
+
+ override def empty: Repr = null.asInstanceOf[Repr]
+ }
+
+ case class JMapWrapper[A, B](val underlying : ju.Map[A, B]) extends mutable.AbstractMap[A, B] with JMapWrapperLike[A, B, JMapWrapper[A, B]] {
+ override def empty = JMapWrapper(new ju.HashMap[A, B])
+ }
+
+ class ConcurrentMapDeprecatedWrapper[A, B](override val underlying: mutable.ConcurrentMap[A, B]) extends MutableMapWrapper[A, B](underlying) with juc.ConcurrentMap[A, 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) = try {
+ underlying.remove(k.asInstanceOf[A], v.asInstanceOf[B])
+ } catch {
+ case ex: ClassCastException =>
+ false
+ }
+
+ 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)
+ }
+
+ class ConcurrentMapWrapper[A, B](override val underlying: concurrent.Map[A, B]) extends MutableMapWrapper[A, B](underlying) with juc.ConcurrentMap[A, 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) = try {
+ underlying.remove(k.asInstanceOf[A], v.asInstanceOf[B])
+ } catch {
+ case ex: ClassCastException =>
+ false
+ }
+
+ 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 JConcurrentMapDeprecatedWrapper[A, B](val underlying: juc.ConcurrentMap[A, B]) extends mutable.AbstractMap[A, B] with JMapWrapperLike[A, B, JConcurrentMapDeprecatedWrapper[A, B]] 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 JConcurrentMapDeprecatedWrapper(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 JConcurrentMapWrapper[A, B](val underlying: juc.ConcurrentMap[A, B]) extends mutable.AbstractMap[A, B] with JMapWrapperLike[A, B, JConcurrentMapWrapper[A, B]] with concurrent.Map[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 DictionaryWrapper[A, B](underlying: mutable.Map[A, B]) extends ju.Dictionary[A, B] {
+ def size: Int = underlying.size
+ def isEmpty: Boolean = underlying.isEmpty
+ def keys: ju.Enumeration[A] = asJavaEnumeration(underlying.keysIterator)
+ def elements: ju.Enumeration[B] = asJavaEnumeration(underlying.valuesIterator)
+ def get(key: AnyRef) = try {
+ underlying get key.asInstanceOf[A] match {
+ case None => null.asInstanceOf[B]
+ case Some(v) => v
+ }
+ } catch {
+ case ex: ClassCastException => null.asInstanceOf[B]
+ }
+ def put(key: A, value: B): B = underlying.put(key, value) match {
+ case Some(v) => v
+ case None => null.asInstanceOf[B]
+ }
+ override def remove(key: AnyRef) = try {
+ underlying remove key.asInstanceOf[A] match {
+ case None => null.asInstanceOf[B]
+ case Some(v) => v
+ }
+ } catch {
+ case ex: ClassCastException => null.asInstanceOf[B]
+ }
+ }
+
+ case class JDictionaryWrapper[A, B](underlying: ju.Dictionary[A, B]) extends mutable.AbstractMap[A, B] with mutable.Map[A, B] {
+ override def size: Int = underlying.size
+
+ def get(k: A) = {
+ val v = underlying get k
+ if (v != null) Some(v) else None
+ }
+
+ def +=(kv: (A, B)): this.type = { underlying.put(kv._1, kv._2); this }
+ def -=(key: A): this.type = { underlying remove key; this }
+
+ override def put(k: A, v: B): Option[B] = {
+ val r = underlying.put(k, v)
+ if (r != null) Some(r) else None
+ }
+
+ override def update(k: A, v: B) { underlying.put(k, v) }
+
+ override def remove(k: A): Option[B] = {
+ val r = underlying remove k
+ if (r != null) Some(r) else None
+ }
+
+ def iterator = enumerationAsScalaIterator(underlying.keys) map (k => (k, underlying get k))
+
+ override def clear() = underlying.clear()
+ }
+
+ case class JPropertiesWrapper(underlying: ju.Properties) extends mutable.AbstractMap[String, String]
+ with 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: Iterator[(String, String)] = new AbstractIterator[(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)
+ }
+}
+
+object Wrappers extends Wrappers
diff --git a/src/library/scala/collection/convert/package.scala b/src/library/scala/collection/convert/package.scala
new file mode 100644
index 0000000000..2f8bca1e1f
--- /dev/null
+++ b/src/library/scala/collection/convert/package.scala
@@ -0,0 +1,18 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2011, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.collection
+
+package object convert {
+ val decorateAsJava = new DecorateAsJava { }
+ val decorateAsScala = new DecorateAsScala { }
+ val decorateAll = new DecorateAsJava with DecorateAsScala { }
+ val wrapAsJava = new WrapAsJava { }
+ val wrapAsScala = new WrapAsScala { }
+ val wrapAll = new WrapAsJava with WrapAsScala { }
+}
diff --git a/src/library/scala/collection/generic/GenericTraversableTemplate.scala b/src/library/scala/collection/generic/GenericTraversableTemplate.scala
index 7333074778..6586434924 100644
--- a/src/library/scala/collection/generic/GenericTraversableTemplate.scala
+++ b/src/library/scala/collection/generic/GenericTraversableTemplate.scala
@@ -119,22 +119,25 @@ trait GenericTraversableTemplate[+A, +CC[X] <: GenTraversable[X]] extends HasNew
* a $coll formed by the elements of these traversable
* collections.
*
- * The resulting collection's type will be guided by the
- * static type of $coll. For example:
- *
- * {{{
- * val xs = List(Set(1, 2, 3), Set(1, 2, 3))
- * // xs == List(1, 2, 3, 1, 2, 3)
- *
- * val ys = Set(List(1, 2, 3), List(3, 2, 1))
- * // ys == Set(1, 2, 3)
- * }}}
- *
* @tparam B the type of the elements of each traversable collection.
* @param asTraversable an implicit conversion which asserts that the element
* type of this $coll is a `GenTraversable`.
* @return a new $coll resulting from concatenating all element ${coll}s.
+ *
* @usecase def flatten[B]: $Coll[B]
+ *
+ * @inheritdoc
+ *
+ * The resulting collection's type will be guided by the
+ * static type of $coll. For example:
+ *
+ * {{{
+ * val xs = List(Set(1, 2, 3), Set(1, 2, 3))
+ * // xs == List(1, 2, 3, 1, 2, 3)
+ *
+ * val ys = Set(List(1, 2, 3), List(3, 2, 1))
+ * // ys == Set(1, 2, 3)
+ * }}}
*/
def flatten[B](implicit asTraversable: A => /*<:<!!!*/ GenTraversableOnce[B]): CC[B] = {
val b = genericBuilder[B]
diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala
index 381fcf3117..1b75c10113 100644
--- a/src/library/scala/collection/immutable/List.scala
+++ b/src/library/scala/collection/immutable/List.scala
@@ -58,7 +58,7 @@ import java.io._
* @author Martin Odersky and others
* @version 2.8
* @since 1.0
- * @see [["http://docs.scala-lang.org/overviews/collections/concrete-immutable-collection-classes.html#lists" "Scala's Collection Library overview"]]
+ * @see [[http://docs.scala-lang.org/overviews/collections/concrete-immutable-collection-classes.html#lists "Scala's Collection Library overview"]]
* section on `Lists` for more information.
*
* @define coll list
@@ -93,8 +93,12 @@ sealed abstract class List[+A] extends AbstractSeq[A]
* @param x the element to prepend.
* @return a list which contains `x` as first element and
* which continues with this list.
- * @example `1 :: List(2, 3) = List(2, 3).::(1) = List(1, 2, 3)`
+ *
* @usecase def ::(x: A): List[A]
+ * @inheritdoc
+ *
+ * Example:
+ * {{{1 :: List(2, 3) = List(2, 3).::(1) = List(1, 2, 3)}}}
*/
def ::[B >: A] (x: B): List[B] =
new scala.collection.immutable.::(x, this)
@@ -103,8 +107,12 @@ sealed abstract class List[+A] extends AbstractSeq[A]
* @param prefix The list elements to prepend.
* @return a list resulting from the concatenation of the given
* list `prefix` and this list.
- * @example `List(1, 2) ::: List(3, 4) = List(3, 4).:::(List(1, 2)) = List(1, 2, 3, 4)`
+ *
* @usecase def :::(prefix: List[A]): List[A]
+ * @inheritdoc
+ *
+ * Example:
+ * {{{List(1, 2) ::: List(3, 4) = List(3, 4).:::(List(1, 2)) = List(1, 2, 3, 4)}}}
*/
def :::[B >: A](prefix: List[B]): List[B] =
if (isEmpty) prefix
@@ -117,7 +125,9 @@ sealed abstract class List[+A] extends AbstractSeq[A]
*
* @param prefix the prefix to reverse and then prepend
* @return the concatenation of the reversed prefix and the current list.
+ *
* @usecase def reverse_:::(prefix: List[A]): List[A]
+ * @inheritdoc
*/
def reverse_:::[B >: A](prefix: List[B]): List[B] = {
var these: List[B] = this
@@ -137,7 +147,9 @@ sealed abstract class List[+A] extends AbstractSeq[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(f: A => A): List[A]
+ * @inheritdoc
*/
def mapConserve[B >: A <: AnyRef](f: A => B): List[B] = {
@tailrec
diff --git a/src/library/scala/collection/immutable/StringLike.scala b/src/library/scala/collection/immutable/StringLike.scala
index f9697565de..fc4e7bf0a8 100644
--- a/src/library/scala/collection/immutable/StringLike.scala
+++ b/src/library/scala/collection/immutable/StringLike.scala
@@ -207,9 +207,20 @@ self =>
/** You can follow a string with `.r`, turning it into a `Regex`. E.g.
*
- * """A\w*""".r is the regular expression for identifiers starting with `A`.
+ * `"""A\w*""".r` is the regular expression for identifiers starting with `A`.
*/
- def r: Regex = new Regex(toString)
+ def r: Regex = r()
+
+ /** You can follow a string with `.r(g1, ... , gn)`, turning it into a `Regex`,
+ * with group names g1 through gn.
+ *
+ * `"""(\d\d)-(\d\d)-(\d\d\d\d)""".r("month", "day", "year")` matches dates
+ * and provides its subcomponents through groups named "month", "day" and
+ * "year".
+ *
+ * @param groupNames The names of the groups in the pattern, in the order they appear.
+ */
+ def r(groupNames: String*): Regex = new Regex(toString, groupNames: _*)
def toBoolean: Boolean = parseBoolean(toString)
def toByte: Byte = java.lang.Byte.parseByte(toString)
diff --git a/src/library/scala/collection/mutable/FlatArray.scala b/src/library/scala/collection/mutable/FlatArray.scala
index a7f994bf74..3e43b66ecf 100644
--- a/src/library/scala/collection/mutable/FlatArray.scala
+++ b/src/library/scala/collection/mutable/FlatArray.scala
@@ -60,8 +60,15 @@ extends AbstractSeq[T]
*/
object FlatArray {
- def empty[Boxed, Unboxed](elems: Boxed*)
- (implicit boxings: BoxingConversions[Boxed, Unboxed], elemManifest: ClassManifest[Unboxed]): FlatArray[Boxed] = apply()
+ def ofDim[Boxed, Unboxed](size:Int)
+ (implicit boxings: BoxingConversions[Boxed, Unboxed],
+ manifest: ClassManifest[Unboxed]): FlatArray[Boxed] = {
+ val elems = Array.ofDim[Unboxed](size)
+ new FlatArray.Impl(elems, boxings, manifest)
+ }
+
+ def empty[Boxed, Unboxed](implicit boxings: BoxingConversions[Boxed, Unboxed],
+ elemManifest: ClassManifest[Unboxed]): FlatArray[Boxed] = apply()
def apply[Boxed, Unboxed](elems: Boxed*)
(implicit boxings: BoxingConversions[Boxed, Unboxed], elemManifest: ClassManifest[Unboxed]): FlatArray[Boxed] = {
diff --git a/src/library/scala/collection/mutable/Stack.scala b/src/library/scala/collection/mutable/Stack.scala
index 8fad131009..b70df05c55 100644
--- a/src/library/scala/collection/mutable/Stack.scala
+++ b/src/library/scala/collection/mutable/Stack.scala
@@ -44,7 +44,7 @@ object Stack extends SeqFactory[Stack] {
* @author Martin Odersky
* @version 2.8
* @since 1
- * @see [[http://docs.scala-lang.org/overviews/collections/concrete-mutable-collection-classes.html#stacks"Scala's Collection Library overview"]]
+ * @see [[http://docs.scala-lang.org/overviews/collections/concrete-mutable-collection-classes.html#stacks "Scala's Collection Library overview"]]
* section on `Stacks` for more information.
* @define Coll Stack
* @define coll stack
diff --git a/src/library/scala/collection/mutable/WeakHashMap.scala b/src/library/scala/collection/mutable/WeakHashMap.scala
index 89d7c7a695..4e09755acf 100644
--- a/src/library/scala/collection/mutable/WeakHashMap.scala
+++ b/src/library/scala/collection/mutable/WeakHashMap.scala
@@ -6,14 +6,11 @@
** |/ **
\* */
-
-
package scala.collection
package mutable
-import JavaConversions._
import generic._
-
+import convert.Wrappers._
/** A hash map with references to entries which are weakly reachable. Entries are
* removed from this map when the key is no longer (strongly) referenced. This class wraps
diff --git a/src/library/scala/collection/parallel/ParIterableLike.scala b/src/library/scala/collection/parallel/ParIterableLike.scala
index 7e0fa366ab..5551c04ce2 100644
--- a/src/library/scala/collection/parallel/ParIterableLike.scala
+++ b/src/library/scala/collection/parallel/ParIterableLike.scala
@@ -668,8 +668,9 @@ self: ParIterableLike[T, Repr, Sequential] =>
* @return a collection containing the prefix scan of the elements in the original collection
*
* @usecase def scan(z: T)(op: (T, T) => T): $Coll[T]
+ * @inheritdoc
*
- * @return a new $coll containing the prefix scan of the elements in this $coll
+ * @return a new $coll containing the prefix scan of the elements in this $coll
*/
def scan[U >: T, That](z: U)(op: (U, U) => U)(implicit bf: CanBuildFrom[Repr, U, That]): That = if (bf(repr).isCombiner) {
if (tasksupport.parallelismLevel > 1) {
diff --git a/src/library/scala/collection/parallel/ParSeqLike.scala b/src/library/scala/collection/parallel/ParSeqLike.scala
index 9f28a286ca..b3c527da84 100644
--- a/src/library/scala/collection/parallel/ParSeqLike.scala
+++ b/src/library/scala/collection/parallel/ParSeqLike.scala
@@ -285,7 +285,6 @@ self =>
}
/** Computes the multiset intersection between this $coll and another sequence.
- * $mayNotTerminateInf
*
* @param that the sequence of elements to intersect with.
* @tparam B the element type of the returned $coll.
@@ -296,12 +295,17 @@ self =>
* If an element value `x` appears
* ''n'' times in `that`, then the first ''n'' occurrences of `x` will be retained
* in the result, but any following occurrences will be omitted.
+ *
* @usecase def intersect(that: Seq[T]): $Coll[T]
- * @return a new $coll which contains all elements of this $coll
- * which also appear in `that`.
- * If an element value `x` appears
- * ''n'' times in `that`, then the first ''n'' occurrences of `x` will be retained
- * in the result, but any following occurrences will be omitted.
+ * @inheritdoc
+ *
+ * $mayNotTerminateInf
+ *
+ * @return a new $coll which contains all elements of this $coll
+ * which also appear in `that`.
+ * If an element value `x` appears
+ * ''n'' times in `that`, then the first ''n'' occurrences of `x` will be retained
+ * in the result, but any following occurrences will be omitted.
*/
def intersect[U >: T](that: GenSeq[U]) = sequentially {
_ intersect that
diff --git a/src/library/scala/collection/parallel/immutable/ParHashMap.scala b/src/library/scala/collection/parallel/immutable/ParHashMap.scala
index 49b00bebdb..e630a9dbed 100644
--- a/src/library/scala/collection/parallel/immutable/ParHashMap.scala
+++ b/src/library/scala/collection/parallel/immutable/ParHashMap.scala
@@ -36,7 +36,9 @@ import collection.parallel.Task
*
* @author Aleksandar Prokopec
* @since 2.9
- *
+ * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_hash_tries Scala's Parallel Collections Library overview]]
+ * section on Parallel Hash Tries for more information.
+ *
* @define Coll immutable.ParHashMap
* @define coll immutable parallel hash map
*/
diff --git a/src/library/scala/collection/parallel/immutable/ParHashSet.scala b/src/library/scala/collection/parallel/immutable/ParHashSet.scala
index 11d92a27c9..084637c5dc 100644
--- a/src/library/scala/collection/parallel/immutable/ParHashSet.scala
+++ b/src/library/scala/collection/parallel/immutable/ParHashSet.scala
@@ -35,6 +35,8 @@ import collection.parallel.Task
*
* @author Aleksandar Prokopec
* @since 2.9
+ * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_hash_tries Scala's Parallel Collections Library overview]]
+ * section on Parallel Hash Tries for more information.
*
* @define Coll immutable.ParHashSet
* @define coll immutable parallel hash set
diff --git a/src/library/scala/collection/parallel/immutable/ParRange.scala b/src/library/scala/collection/parallel/immutable/ParRange.scala
index 9cac433460..277fd5fdd3 100644
--- a/src/library/scala/collection/parallel/immutable/ParRange.scala
+++ b/src/library/scala/collection/parallel/immutable/ParRange.scala
@@ -25,6 +25,8 @@ import scala.collection.Iterator
*
* @author Aleksandar Prokopec
* @since 2.9
+ * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_range Scala's Parallel Collections Library overview]]
+ * section on `ParRange` for more information.
*
* @define Coll immutable.ParRange
* @define coll immutable parallel range
diff --git a/src/library/scala/collection/parallel/immutable/ParVector.scala b/src/library/scala/collection/parallel/immutable/ParVector.scala
index 5d9c431bc1..8baa84b77c 100644
--- a/src/library/scala/collection/parallel/immutable/ParVector.scala
+++ b/src/library/scala/collection/parallel/immutable/ParVector.scala
@@ -34,6 +34,8 @@ import immutable.VectorIterator
*
* @author Aleksandar Prokopec
* @since 2.9
+ * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_vector Scala's Parallel Collections Library overview]]
+ * section on `ParVector` for more information.
*
* @define Coll immutable.ParVector
* @define coll immutable parallel vector
diff --git a/src/library/scala/collection/parallel/mutable/ParArray.scala b/src/library/scala/collection/parallel/mutable/ParArray.scala
index c33495bd39..8cc0b95997 100644
--- a/src/library/scala/collection/parallel/mutable/ParArray.scala
+++ b/src/library/scala/collection/parallel/mutable/ParArray.scala
@@ -44,10 +44,14 @@ import scala.collection.GenTraversableOnce
*
* @tparam T type of the elements in the array
*
+ * @author Aleksandar Prokopec
+ * @since 2.9
+ * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_array Scala's Parallel Collections Library overview]]
+ * section on `ParArray` for more information.
+ *
* @define Coll ParArray
* @define coll parallel array
*
- * @author Aleksandar Prokopec
*/
@SerialVersionUID(1L)
class ParArray[T] private[mutable] (val arrayseq: ArraySeq[T])
diff --git a/src/library/scala/collection/parallel/mutable/ParHashMap.scala b/src/library/scala/collection/parallel/mutable/ParHashMap.scala
index 6ce6c45460..23b23d55a1 100644
--- a/src/library/scala/collection/parallel/mutable/ParHashMap.scala
+++ b/src/library/scala/collection/parallel/mutable/ParHashMap.scala
@@ -32,6 +32,8 @@ import collection.parallel.Task
* @define coll parallel hash map
*
* @author Aleksandar Prokopec
+ * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_hash_tables Scala's Parallel Collections Library overview]]
+ * section on Parallel Hash Tables for more information.
*/
@SerialVersionUID(1L)
class ParHashMap[K, V] private[collection] (contents: HashTable.Contents[K, DefaultEntry[K, V]])
diff --git a/src/library/scala/collection/parallel/mutable/ParHashSet.scala b/src/library/scala/collection/parallel/mutable/ParHashSet.scala
index e0a2ab03df..4e9a38c13f 100644
--- a/src/library/scala/collection/parallel/mutable/ParHashSet.scala
+++ b/src/library/scala/collection/parallel/mutable/ParHashSet.scala
@@ -29,6 +29,8 @@ import collection.parallel.Task
* @define coll parallel hash set
*
* @author Aleksandar Prokopec
+ * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_hash_tables Scala's Parallel Collections Library overview]]
+ * section on Parallel Hash Tables for more information.
*/
@SerialVersionUID(1L)
class ParHashSet[T] private[collection] (contents: FlatHashTable.Contents[T])
diff --git a/src/library/scala/collection/parallel/mutable/ParTrieMap.scala b/src/library/scala/collection/parallel/mutable/ParTrieMap.scala
index fa19990b91..359c35f1dd 100644
--- a/src/library/scala/collection/parallel/mutable/ParTrieMap.scala
+++ b/src/library/scala/collection/parallel/mutable/ParTrieMap.scala
@@ -33,6 +33,8 @@ import scala.collection.concurrent.TrieMapIterator
*
* @author Aleksandar Prokopec
* @since 2.10
+ * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_concurrent_tries Scala's Parallel Collections Library overview]]
+ * section on `ParTrieMap` for more information.
*/
final class ParTrieMap[K, V] private[collection] (private val ctrie: TrieMap[K, V])
extends ParMap[K, V]
diff --git a/src/library/scala/concurrent/Awaitable.scala b/src/library/scala/concurrent/Awaitable.scala
index c38e668f30..052e6e2366 100644
--- a/src/library/scala/concurrent/Awaitable.scala
+++ b/src/library/scala/concurrent/Awaitable.scala
@@ -11,13 +11,18 @@ package scala.concurrent
import scala.annotation.implicitNotFound
-import scala.util.Duration
+import scala.concurrent.util.Duration
trait Awaitable[+T] {
- @implicitNotFound(msg = "Waiting must be done by calling `blocking(timeout) b`, where `b` is the `Awaitable` object or a potentially blocking piece of code.")
- def await(atMost: Duration)(implicit canawait: CanAwait): T
+ def ready(atMost: Duration)(implicit permit: CanAwait): this.type
+
+ /**
+ * Throws exceptions if cannot produce a T within the specified time
+ * This method should not be called directly.
+ */
+ def result(atMost: Duration)(implicit permit: CanAwait): T
}
diff --git a/src/library/scala/concurrent/ConcurrentPackageObject.scala b/src/library/scala/concurrent/ConcurrentPackageObject.scala
index 7d005838d3..ba98757906 100644
--- a/src/library/scala/concurrent/ConcurrentPackageObject.scala
+++ b/src/library/scala/concurrent/ConcurrentPackageObject.scala
@@ -12,7 +12,8 @@ package scala.concurrent
import java.util.concurrent.{ Executors, ExecutorService }
import scala.concurrent.forkjoin.ForkJoinPool
-import scala.util.{ Duration, Try, Success, Failure }
+import scala.util.{ Try, Success, Failure }
+import scala.concurrent.util.Duration
import ConcurrentPackageObject._
@@ -26,8 +27,8 @@ abstract class ConcurrentPackageObject {
new impl.ExecutionContextImpl(getExecutorService)
private[concurrent] def getExecutorService: AnyRef =
- if (util.Properties.isJavaAtLeast("1.6")) {
- val vendor = util.Properties.javaVmVendor
+ if (scala.util.Properties.isJavaAtLeast("1.6")) {
+ val vendor = scala.util.Properties.javaVmVendor
if ((vendor contains "Oracle") || (vendor contains "Sun") || (vendor contains "Apple")) new ForkJoinPool
else Executors.newCachedThreadPool()
} else Executors.newCachedThreadPool()
@@ -58,14 +59,18 @@ abstract class ConcurrentPackageObject {
/* concurrency constructs */
def future[T](body: =>T)(implicit execCtx: ExecutionContext = executionContext): Future[T] =
- execCtx future body
+ Future[T](body)
def promise[T]()(implicit execCtx: ExecutionContext = executionContext): Promise[T] =
- execCtx promise
+ Promise[T]()
/** Wraps a block of code into an awaitable object. */
def body2awaitable[T](body: =>T) = new Awaitable[T] {
- def await(atMost: Duration)(implicit cb: CanAwait) = body
+ def ready(atMost: Duration)(implicit permit: CanAwait) = {
+ body
+ this
+ }
+ def result(atMost: Duration)(implicit permit: CanAwait) = body
}
/** Used to block on a piece of code which potentially blocks.
@@ -77,8 +82,8 @@ abstract class ConcurrentPackageObject {
* - InterruptedException - in the case that a wait within the blockable object was interrupted
* - TimeoutException - in the case that the blockable object timed out
*/
- def blocking[T](atMost: Duration)(body: =>T)(implicit execCtx: ExecutionContext): T =
- executionContext.blocking(atMost)(body)
+ def blocking[T](body: =>T)(implicit execCtx: ExecutionContext): T =
+ executionContext.blocking(body)
/** Blocks on an awaitable object.
*
diff --git a/src/library/scala/concurrent/DelayedLazyVal.scala b/src/library/scala/concurrent/DelayedLazyVal.scala
index a17153bad5..96a66d83b6 100644
--- a/src/library/scala/concurrent/DelayedLazyVal.scala
+++ b/src/library/scala/concurrent/DelayedLazyVal.scala
@@ -40,9 +40,8 @@ class DelayedLazyVal[T](f: () => T, body: => Unit) {
def apply(): T = if (isDone) complete else f()
// TODO replace with scala.concurrent.future { ... }
- ops.future {
+ future {
body
_isDone = true
}
-
}
diff --git a/src/library/scala/concurrent/ExecutionContext.scala b/src/library/scala/concurrent/ExecutionContext.scala
index eb1b3355c0..a206a2d4ea 100644
--- a/src/library/scala/concurrent/ExecutionContext.scala
+++ b/src/library/scala/concurrent/ExecutionContext.scala
@@ -12,7 +12,7 @@ package scala.concurrent
import java.util.concurrent.atomic.{ AtomicInteger }
import java.util.concurrent.{ Executors, Future => JFuture, Callable }
-import scala.util.Duration
+import scala.concurrent.util.Duration
import scala.util.{ Try, Success, Failure }
import scala.concurrent.forkjoin.{ ForkJoinPool, RecursiveTask => FJTask, RecursiveAction, ForkJoinWorkerThread }
import scala.collection.generic.CanBuildFrom
@@ -22,19 +22,11 @@ import collection._
trait ExecutionContext {
- protected implicit object CanAwaitEvidence extends CanAwait
-
def execute(runnable: Runnable): Unit
def execute[U](body: () => U): Unit
- def promise[T]: Promise[T]
-
- def future[T](body: Callable[T]): Future[T] = future(body.call())
-
- def future[T](body: => T): Future[T]
-
- def blocking[T](atMost: Duration)(body: =>T): T
+ def blocking[T](body: =>T): T
def blocking[T](awaitable: Awaitable[T], atMost: Duration): T
@@ -44,89 +36,8 @@ trait ExecutionContext {
private implicit val executionContext = this
- def keptPromise[T](result: T): Promise[T] = {
- val p = promise[T]
- p success result
- }
-
- def brokenPromise[T](t: Throwable): Promise[T] = {
- val p = promise[T]
- p failure t
- }
-
- /** TODO some docs
- *
- */
- def all[T, Coll[X] <: Traversable[X]](futures: Coll[Future[T]])(implicit cbf: CanBuildFrom[Coll[_], T, Coll[T]]): Future[Coll[T]] = {
- import nondeterministic._
- val buffer = new mutable.ArrayBuffer[T]
- val counter = new AtomicInteger(1) // how else could we do this?
- val p: Promise[Coll[T]] = promise[Coll[T]] // we need an implicit execctx in the signature
- var idx = 0
-
- def tryFinish() = if (counter.decrementAndGet() == 0) {
- val builder = cbf(futures)
- builder ++= buffer
- p success builder.result
- }
-
- for (f <- futures) {
- val currentIndex = idx
- buffer += null.asInstanceOf[T]
- counter.incrementAndGet()
- f onComplete {
- case Failure(t) =>
- p tryFailure t
- case Success(v) =>
- buffer(currentIndex) = v
- tryFinish()
- }
- idx += 1
- }
-
- tryFinish()
-
- p.future
- }
-
- /** TODO some docs
- *
- */
- def any[T](futures: Traversable[Future[T]]): Future[T] = {
- val p = promise[T]
- val completeFirst: Try[T] => Unit = elem => p tryComplete elem
-
- futures foreach (_ onComplete completeFirst)
-
- p.future
- }
-
- /** TODO some docs
- *
- */
- def find[T](futures: Traversable[Future[T]])(predicate: T => Boolean): Future[Option[T]] = {
- if (futures.isEmpty) Promise.kept[Option[T]](None).future
- else {
- val result = promise[Option[T]]
- val count = new AtomicInteger(futures.size)
- val search: Try[T] => Unit = {
- v => v match {
- case Success(r) => if (predicate(r)) result trySuccess Some(r)
- case _ =>
- }
- if (count.decrementAndGet() == 0) result trySuccess None
- }
-
- futures.foreach(_ onComplete search)
-
- result.future
- }
- }
-
}
-sealed trait CanAwait
-
diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala
index eb54b61db0..d73801aa90 100644
--- a/src/library/scala/concurrent/Future.scala
+++ b/src/library/scala/concurrent/Future.scala
@@ -17,7 +17,8 @@ import java.util.{ LinkedList => JLinkedList }
import java.{ lang => jl }
import java.util.concurrent.atomic.{ AtomicReferenceFieldUpdater, AtomicInteger, AtomicBoolean }
-import scala.util.{ Timeout, Duration, Try, Success, Failure }
+import scala.util.{ Try, Success, Failure }
+import scala.concurrent.util.Duration
import scala.Option
import scala.annotation.tailrec
@@ -133,8 +134,26 @@ self =>
/** Creates a new promise.
*/
def newPromise[S]: Promise[S]
-
-
+
+ /** Returns whether the future has already been completed with
+ * a value or an exception.
+ *
+ * $nonDeterministic
+ *
+ * @return `true` if the future is already completed, `false` otherwise
+ */
+ def isCompleted: Boolean
+
+ /** The value of this `Future`.
+ *
+ * If the future is not completed the returned value will be `None`.
+ * If the future is completed the value will be `Some(Success(t))`
+ * if it contains a valid result, or `Some(Failure(error))` if it contains
+ * an exception.
+ */
+ def value: Option[Try[T]]
+
+
/* Projections */
/** Returns a failed projection of this future.
@@ -234,8 +253,8 @@ self =>
* val f = future { 5 }
* val g = f filter { _ % 2 == 1 }
* val h = f filter { _ % 2 == 0 }
- * await(0) g // evaluates to 5
- * await(0) h // throw a NoSuchElementException
+ * await(g, 0) // evaluates to 5
+ * await(h, 0) // throw a NoSuchElementException
* }}}
*/
def filter(pred: T => Boolean): Future[T] = {
@@ -271,8 +290,8 @@ self =>
* val h = f collect {
* case x if x > 0 => x * 2
* }
- * await(0) g // evaluates to 5
- * await(0) h // throw a NoSuchElementException
+ * await(g, 0) // evaluates to 5
+ * await(h, 0) // throw a NoSuchElementException
* }}}
*/
def collect[S](pf: PartialFunction[T, S]): Future[S] = {
@@ -382,7 +401,7 @@ self =>
* val f = future { sys.error("failed") }
* val g = future { 5 }
* val h = f orElse g
- * await(0) h // evaluates to 5
+ * await(h, 0) // evaluates to 5
* }}}
*/
def fallbackTo[U >: T](that: Future[U]): Future[U] = {
@@ -444,7 +463,7 @@ self =>
* val f = future { sys.error("failed") }
* val g = future { 5 }
* val h = f either g
- * await(0) h // evaluates to either 5 or throws a runtime exception
+ * await(h, 0) // evaluates to either 5 or throws a runtime exception
* }}}
*/
def either[U >: T](that: Future[U]): Future[U] = {
@@ -465,26 +484,102 @@ self =>
-/** TODO some docs
+/** Future companion object.
*
* @define nonDeterministic
* Note: using this method yields nondeterministic dataflow programs.
*/
object Future {
+
+ def apply[T](body: =>T)(implicit executor: ExecutionContext): Future[T] = impl.Future(body)
+
+ import scala.collection.mutable.Builder
+ import scala.collection.generic.CanBuildFrom
+
+ /** Simple version of `Futures.traverse`. Transforms a `Traversable[Future[A]]` into a `Future[Traversable[A]]`.
+ * Useful for reducing many `Future`s into a single `Future`.
+ */
+ def sequence[A, M[_] <: Traversable[_]](in: M[Future[A]])(implicit cbf: CanBuildFrom[M[Future[A]], A, M[A]], executor: ExecutionContext): Future[M[A]] = {
+ in.foldLeft(Promise.successful(cbf(in)).future) {
+ (fr, fa) => for (r <- fr; a <- fa.asInstanceOf[Future[A]]) yield (r += a)
+ } map (_.result)
+ }
+
+ /** Returns a `Future` to the result of the first future in the list that is completed.
+ */
+ def firstCompletedOf[T](futures: Traversable[Future[T]])(implicit executor: ExecutionContext): Future[T] = {
+ val p = Promise[T]()
+
+ val completeFirst: Try[T] => Unit = p tryComplete _
+ futures.foreach(_ onComplete completeFirst)
- // TODO make more modular by encoding all other helper methods within the execution context
- /** TODO some docs
+ p.future
+ }
+
+ /** Returns a `Future` that will hold the optional result of the first `Future` with a result that matches the predicate.
*/
- def all[T, Coll[X] <: Traversable[X]](futures: Coll[Future[T]])(implicit cbf: CanBuildFrom[Coll[_], T, Coll[T]], ec: ExecutionContext): Future[Coll[T]] =
- ec.all[T, Coll](futures)
+ def find[T](futures: Traversable[Future[T]])(predicate: T => Boolean)(implicit executor: ExecutionContext): Future[Option[T]] = {
+ if (futures.isEmpty) Promise.successful[Option[T]](None).future
+ else {
+ val result = Promise[Option[T]]()
+ val ref = new AtomicInteger(futures.size)
+ val search: Try[T] => Unit = v => try {
+ v match {
+ case Success(r) => if (predicate(r)) result tryComplete Success(Some(r))
+ case _ =>
+ }
+ } finally {
+ if (ref.decrementAndGet == 0)
+ result tryComplete Success(None)
+ }
- // move this to future companion object
- @inline def apply[T](body: =>T)(implicit executor: ExecutionContext): Future[T] = executor.future(body)
+ futures.foreach(_ onComplete search)
- def any[T](futures: Traversable[Future[T]])(implicit ec: ExecutionContext): Future[T] = ec.any(futures)
+ result.future
+ }
+ }
- def find[T](futures: Traversable[Future[T]])(predicate: T => Boolean)(implicit ec: ExecutionContext): Future[Option[T]] = ec.find(futures)(predicate)
+ /** A non-blocking fold over the specified futures, with the start value of the given zero.
+ * The fold is performed on the thread where the last future is completed,
+ * the result will be the first failure of any of the futures, or any failure in the actual fold,
+ * or the result of the fold.
+ *
+ * Example:
+ * {{{
+ * val result = Await.result(Future.fold(futures)(0)(_ + _), 5 seconds)
+ * }}}
+ */
+ def fold[T, R](futures: Traversable[Future[T]])(zero: R)(foldFun: (R, T) => R)(implicit executor: ExecutionContext): Future[R] = {
+ if (futures.isEmpty) Promise.successful(zero).future
+ else sequence(futures).map(_.foldLeft(zero)(foldFun))
+ }
+ /** Initiates a fold over the supplied futures where the fold-zero is the result value of the `Future` that's completed first.
+ *
+ * Example:
+ * {{{
+ * val result = Await.result(Futures.reduce(futures)(_ + _), 5 seconds)
+ * }}}
+ */
+ def reduce[T, R >: T](futures: Traversable[Future[T]])(op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] = {
+ if (futures.isEmpty) Promise[R].failure(new NoSuchElementException("reduce attempted on empty collection")).future
+ else sequence(futures).map(_ reduceLeft op)
+ }
+
+ /** Transforms a `Traversable[A]` into a `Future[Traversable[B]]` using the provided function `A => Future[B]`.
+ * This is useful for performing a parallel map. For example, to apply a function to all items of a list
+ * in parallel:
+ *
+ * {{{
+ * val myFutureList = Future.traverse(myList)(x => Future(myFunc(x)))
+ * }}}
+ */
+ def traverse[A, B, M[_] <: Traversable[_]](in: M[A])(fn: A => Future[B])(implicit cbf: CanBuildFrom[M[A], B, M[B]], executor: ExecutionContext): Future[M[B]] =
+ in.foldLeft(Promise.successful(cbf(in)).future) { (fr, a) =>
+ val fb = fn(a.asInstanceOf[A])
+ for (r <- fr; b <- fb) yield (r += b)
+ }.map(_.result)
+
}
diff --git a/src/library/scala/concurrent/Promise.scala b/src/library/scala/concurrent/Promise.scala
index 4404e90971..61e21606e6 100644
--- a/src/library/scala/concurrent/Promise.scala
+++ b/src/library/scala/concurrent/Promise.scala
@@ -30,8 +30,6 @@ import scala.util.{ Try, Success, Failure }
*/
trait Promise[T] {
- import nondeterministic._
-
/** Future containing the value of this promise.
*/
def future: Future[T]
@@ -114,12 +112,18 @@ trait Promise[T] {
object Promise {
- def kept[T](result: T)(implicit execctx: ExecutionContext): Promise[T] =
- execctx keptPromise result
+ /** Creates a new promise.
+ */
+ def apply[T]()(implicit executor: ExecutionContext): Promise[T] = new impl.Promise.DefaultPromise[T]()
- def broken[T](t: Throwable)(implicit execctx: ExecutionContext): Promise[T] =
- execctx brokenPromise t
+ /** Creates an already completed Promise with the specified exception
+ */
+ def failed[T](exception: Throwable)(implicit executor: ExecutionContext): Promise[T] = new impl.Promise.KeptPromise[T](Failure(exception))
+ /** Creates an already completed Promise with the specified result
+ */
+ def successful[T](result: T)(implicit executor: ExecutionContext): Promise[T] = new impl.Promise.KeptPromise[T](Success(result))
+
}
diff --git a/src/library/scala/concurrent/Scheduler.scala b/src/library/scala/concurrent/Scheduler.scala
index 39d798e6b4..e2eb4d69fe 100644
--- a/src/library/scala/concurrent/Scheduler.scala
+++ b/src/library/scala/concurrent/Scheduler.scala
@@ -8,7 +8,7 @@
package scala.concurrent
-import scala.util.Duration
+import scala.concurrent.util.Duration
/** A service for scheduling tasks and thunks for one-time, or periodic execution.
*/
diff --git a/src/library/scala/concurrent/default/SchedulerImpl.scala.disabled b/src/library/scala/concurrent/default/SchedulerImpl.scala.disabled
index 745d2d1a15..241efa8857 100644
--- a/src/library/scala/concurrent/default/SchedulerImpl.scala.disabled
+++ b/src/library/scala/concurrent/default/SchedulerImpl.scala.disabled
@@ -9,7 +9,7 @@
package scala.concurrent
package default
-import scala.util.Duration
+import scala.concurrent.util.Duration
private[concurrent] final class SchedulerImpl extends Scheduler {
private val timer =
diff --git a/src/library/scala/concurrent/default/TaskImpl.scala.disabled b/src/library/scala/concurrent/default/TaskImpl.scala.disabled
index 94e54cb372..50753a7154 100644
--- a/src/library/scala/concurrent/default/TaskImpl.scala.disabled
+++ b/src/library/scala/concurrent/default/TaskImpl.scala.disabled
@@ -7,7 +7,7 @@ import java.util.concurrent.atomic.AtomicReferenceFieldUpdater
import scala.concurrent.forkjoin.{ ForkJoinPool, RecursiveAction, ForkJoinWorkerThread }
import scala.util.Try
import scala.util
-import scala.util.Duration
+import scala.concurrent.util.Duration
import scala.annotation.tailrec
diff --git a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala
index 6201de14d7..5dc440f42b 100644
--- a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala
+++ b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala
@@ -13,8 +13,8 @@ package scala.concurrent.impl
import java.util.concurrent.{Callable, ExecutorService}
import scala.concurrent.forkjoin._
import scala.concurrent.{ExecutionContext, resolver, Awaitable, body2awaitable}
-import scala.util.{ Duration, Try, Success, Failure }
-import scala.collection.mutable.Stack
+import scala.util.{ Try, Success, Failure }
+import scala.concurrent.util.{ Duration }
@@ -37,32 +37,12 @@ private[scala] class ExecutionContextImpl(val executorService: AnyRef) extends E
def run() = body()
})
- def promise[T]: Promise[T] = new Promise.DefaultPromise[T]()(this)
-
- def future[T](body: =>T): Future[T] = {
- val p = promise[T]
-
- dispatchFuture {
- () =>
- p complete {
- try {
- Success(body)
- } catch {
- case e => resolver(e)
- }
- }
- }
-
- p.future
- }
-
- def blocking[T](atMost: Duration)(body: =>T): T = blocking(body2awaitable(body), atMost)
+ def blocking[T](body: =>T): T = blocking(body2awaitable(body), Duration.fromNanos(0))
def blocking[T](awaitable: Awaitable[T], atMost: Duration): T = {
- currentExecutionContext.get match {
- case null => awaitable.await(atMost)(null) // outside - TODO - fix timeout case
- case x => x.blockingCall(awaitable) // inside an execution context thread
- }
+ Future.releaseStack(this)
+
+ awaitable.result(atMost)(scala.concurrent.Await.canAwaitEvidence)
}
def reportFailure(t: Throwable) = t match {
@@ -70,61 +50,6 @@ private[scala] class ExecutionContextImpl(val executorService: AnyRef) extends E
case t => t.printStackTrace()
}
- /** Only callable from the tasks running on the same execution context. */
- private def blockingCall[T](body: Awaitable[T]): T = {
- releaseStack()
-
- // TODO see what to do with timeout
- body.await(Duration.fromNanos(0))(CanAwaitEvidence)
- }
-
- // an optimization for batching futures
- // TODO we should replace this with a public queue,
- // so that it can be stolen from
- // OR: a push to the local task queue should be so cheap that this is
- // not even needed, but stealing is still possible
- private val _taskStack = new ThreadLocal[Stack[() => Unit]]()
-
- private def releaseStack(): Unit =
- _taskStack.get match {
- case stack if (stack ne null) && stack.nonEmpty =>
- val tasks = stack.elems
- stack.clear()
- _taskStack.remove()
- dispatchFuture(() => _taskStack.get.elems = tasks, true)
- case null =>
- // do nothing - there is no local batching stack anymore
- case _ =>
- _taskStack.remove()
- }
-
- private[impl] def dispatchFuture(task: () => Unit, force: Boolean = false): Unit =
- _taskStack.get match {
- case stack if (stack ne null) && !force => stack push task
- case _ => this.execute(
- new Runnable {
- def run() {
- try {
- val taskStack = Stack[() => Unit](task)
- _taskStack set taskStack
- while (taskStack.nonEmpty) {
- val next = taskStack.pop()
- try {
- next.apply()
- } catch {
- case e =>
- // TODO catching all and continue isn't good for OOME
- reportFailure(e)
- }
- }
- } finally {
- _taskStack.remove()
- }
- }
- }
- )
- }
-
}
diff --git a/src/library/scala/concurrent/impl/Future.scala b/src/library/scala/concurrent/impl/Future.scala
index b4385ea34a..6833b2467f 100644
--- a/src/library/scala/concurrent/impl/Future.scala
+++ b/src/library/scala/concurrent/impl/Future.scala
@@ -8,13 +8,17 @@
package scala.concurrent.impl
+
+
import scala.concurrent.{Awaitable, ExecutionContext}
import scala.util.{ Try, Success, Failure }
-//import scala.util.continuations._
+import scala.collection.mutable.Stack
+
+
private[concurrent] trait Future[+T] extends scala.concurrent.Future[T] with Awaitable[T] {
- implicit def executor: ExecutionContextImpl
+ implicit def executor: ExecutionContext
/** For use only within a Future.flow block or another compatible Delimited Continuations reset block.
*
@@ -40,7 +44,7 @@ private[concurrent] trait Future[+T] extends scala.concurrent.Future[T] with Awa
* that conforms to A's erased type or a ClassCastException otherwise.
*/
final def mapTo[T](implicit m: Manifest[T]) = {
- val p = executor.promise[T]
+ val p = new Promise.DefaultPromise[T]
onComplete {
case f @ Failure(t) => p complete f.asInstanceOf[Try[T]]
@@ -48,7 +52,7 @@ private[concurrent] trait Future[+T] extends scala.concurrent.Future[T] with Awa
p complete (try {
Success(Future.boxedType(m.erasure).cast(v).asInstanceOf[T])
} catch {
- case e: ClassCastException ⇒ Failure(e)
+ case e: ClassCastException => Failure(e)
})
}
@@ -86,4 +90,66 @@ object Future {
def boxedType(c: Class[_]): Class[_] = {
if (c.isPrimitive) toBoxed(c) else c
}
+
+ def apply[T](body: =>T)(implicit executor: ExecutionContext): Future[T] = {
+ val promise = new Promise.DefaultPromise[T]()
+ executor.execute(new Runnable {
+ def run = {
+ promise complete {
+ try {
+ Success(body)
+ } catch {
+ case e => scala.concurrent.resolver(e)
+ }
+ }
+ }
+ })
+ promise.future
+ }
+
+ // an optimization for batching futures
+ // TODO we should replace this with a public queue,
+ // so that it can be stolen from
+ // OR: a push to the local task queue should be so cheap that this is
+ // not even needed, but stealing is still possible
+ private val _taskStack = new ThreadLocal[Stack[() => Unit]]()
+
+ private[impl] def releaseStack(executor: ExecutionContext): Unit =
+ _taskStack.get match {
+ case stack if (stack ne null) && stack.nonEmpty =>
+ val tasks = stack.elems
+ stack.clear()
+ _taskStack.remove()
+ dispatchFuture(executor, () => _taskStack.get.elems = tasks, true)
+ case null =>
+ // do nothing - there is no local batching stack anymore
+ case _ =>
+ _taskStack.remove()
+ }
+
+ private[impl] def dispatchFuture(executor: ExecutionContext, task: () => Unit, force: Boolean = false): Unit =
+ _taskStack.get match {
+ case stack if (stack ne null) && !force => stack push task
+ case _ => executor.execute(new Runnable {
+ def run() {
+ try {
+ val taskStack = Stack[() => Unit](task)
+ _taskStack set taskStack
+ while (taskStack.nonEmpty) {
+ val next = taskStack.pop()
+ try {
+ next.apply()
+ } catch {
+ case e =>
+ // TODO catching all and continue isn't good for OOME
+ executor.reportFailure(e)
+ }
+ }
+ } finally {
+ _taskStack.remove()
+ }
+ }
+ })
+ }
+
}
diff --git a/src/library/scala/concurrent/impl/Promise.scala b/src/library/scala/concurrent/impl/Promise.scala
index 5238bc51db..c79b0d02cc 100644
--- a/src/library/scala/concurrent/impl/Promise.scala
+++ b/src/library/scala/concurrent/impl/Promise.scala
@@ -14,7 +14,7 @@ import java.util.concurrent.TimeUnit.{ NANOSECONDS, MILLISECONDS }
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater
import scala.concurrent.{Awaitable, ExecutionContext, resolve, resolver, blocking, CanAwait, TimeoutException}
//import scala.util.continuations._
-import scala.util.Duration
+import scala.concurrent.util.Duration
import scala.util.Try
import scala.util
import scala.annotation.tailrec
@@ -26,7 +26,7 @@ private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with Fu
def future = this
- def newPromise[S]: Promise[S] = executor promise
+ def newPromise[S]: scala.concurrent.Promise[S] = new Promise.DefaultPromise()
// TODO refine answer and return types here from Any to type parameters
// then move this up in the hierarchy
@@ -75,6 +75,7 @@ private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with Fu
object Promise {
+
def dur2long(dur: Duration): Long = if (dur.isFinite) dur.toNanos else Long.MaxValue
def EmptyPending[T](): FState[T] = emptyPendingValue.asInstanceOf[FState[T]]
@@ -101,7 +102,7 @@ object Promise {
/** Default promise implementation.
*/
- class DefaultPromise[T](implicit val executor: ExecutionContextImpl) extends AbstractPromise with Promise[T] {
+ class DefaultPromise[T](implicit val executor: ExecutionContext) extends AbstractPromise with Promise[T] {
self =>
updater.set(this, Promise.EmptyPending())
@@ -126,14 +127,14 @@ object Promise {
value.isDefined
}
- executor.blocking(concurrent.body2awaitable(awaitUnsafe(dur2long(atMost))), Duration.fromNanos(0))
+ executor.blocking(concurrent.body2awaitable(awaitUnsafe(dur2long(atMost))), atMost)
}
- private def ready(atMost: Duration)(implicit permit: CanAwait): this.type =
+ def ready(atMost: Duration)(implicit permit: CanAwait): this.type =
if (value.isDefined || tryAwait(atMost)) this
else throw new TimeoutException("Futures timed out after [" + atMost.toMillis + "] milliseconds")
- def await(atMost: Duration)(implicit permit: CanAwait): T =
+ def result(atMost: Duration)(implicit permit: CanAwait): T =
ready(atMost).value.get match {
case util.Failure(e) => throw e
case util.Success(r) => r
@@ -176,9 +177,9 @@ object Promise {
case null => false
case cs if cs.isEmpty => true
case cs =>
- executor dispatchFuture {
+ Future.dispatchFuture(executor, {
() => cs.foreach(f => notifyCompleted(f, value))
- }
+ })
true
}
}
@@ -197,9 +198,9 @@ object Promise {
if (tryAddCallback()) {
val result = value.get
- executor dispatchFuture {
+ Future.dispatchFuture(executor, {
() => notifyCompleted(func, result)
- }
+ })
}
this
@@ -218,22 +219,22 @@ object Promise {
*
* Useful in Future-composition when a value to contribute is already available.
*/
- final class KeptPromise[T](suppliedValue: Try[T])(implicit val executor: ExecutionContextImpl) extends Promise[T] {
+ final class KeptPromise[T](suppliedValue: Try[T])(implicit val executor: ExecutionContext) extends Promise[T] {
val value = Some(resolve(suppliedValue))
def tryComplete(value: Try[T]): Boolean = false
def onComplete[U](func: Try[T] => U): this.type = {
val completedAs = value.get
- executor dispatchFuture {
+ Future.dispatchFuture(executor, {
() => func(completedAs)
- }
+ })
this
}
- private def ready(atMost: Duration)(implicit permit: CanAwait): this.type = this
+ def ready(atMost: Duration)(implicit permit: CanAwait): this.type = this
- def await(atMost: Duration)(implicit permit: CanAwait): T = value.get match {
+ def result(atMost: Duration)(implicit permit: CanAwait): T = value.get match {
case util.Failure(e) => throw e
case util.Success(r) => r
}
diff --git a/src/library/scala/concurrent/package.scala b/src/library/scala/concurrent/package.scala
index 7cc48c09b2..e2ae17498f 100644
--- a/src/library/scala/concurrent/package.scala
+++ b/src/library/scala/concurrent/package.scala
@@ -8,7 +8,8 @@
package scala
-import scala.util.{ Duration, Try, Success, Failure }
+import scala.util.{ Try, Success, Failure }
+import scala.concurrent.util.Duration
/** This package object contains primitives for concurrent and parallel programming.
*/
@@ -19,27 +20,17 @@ package object concurrent extends scala.concurrent.ConcurrentPackageObject {
}
package concurrent {
- object await {
- def ready[T](atMost: Duration)(awaitable: Awaitable[T])(implicit execCtx: ExecutionContext = executionContext): Awaitable[T] = {
- try blocking(awaitable, atMost)
- catch { case _ => }
- awaitable
- }
-
- def result[T](atMost: Duration)(awaitable: Awaitable[T])(implicit execCtx: ExecutionContext = executionContext): T = {
- blocking(awaitable, atMost)
- }
+
+ sealed trait CanAwait
+
+ object Await {
+ private[concurrent] implicit val canAwaitEvidence = new CanAwait {}
+
+ def ready[T](awaitable: Awaitable[T], atMost: Duration): Awaitable[T] = awaitable.ready(atMost)
+
+ def result[T](awaitable: Awaitable[T], atMost: Duration): T = awaitable.result(atMost)
}
- /** Importing this object allows using some concurrency primitives
- * on futures and promises that can yield nondeterministic programs.
- *
- * While program determinism is broken when using these primitives,
- * some programs cannot be written without them (e.g. multiple client threads
- * cannot send requests to a server thread through regular promises and futures).
- */
- object nondeterministic { }
-
/** A timeout exception.
*
* Futures are failed with a timeout exception when their timeout expires.
diff --git a/src/library/scala/concurrent/util/Duration.scala b/src/library/scala/concurrent/util/Duration.scala
new file mode 100644
index 0000000000..33d034da76
--- /dev/null
+++ b/src/library/scala/concurrent/util/Duration.scala
@@ -0,0 +1,578 @@
+/**
+ * Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
+ */
+
+package scala.concurrent.util
+
+import java.util.concurrent.TimeUnit
+import TimeUnit._
+import java.lang.{ Double ⇒ JDouble }
+
+object DurationImplicits {
+ trait Classifier[C] {
+ type R
+ def convert(d: FiniteDuration): R
+ }
+
+ object span
+ implicit object spanConvert extends Classifier[span.type] {
+ type R = FiniteDuration
+ def convert(d: FiniteDuration) = d
+ }
+
+ object fromNow
+ implicit object fromNowConvert extends Classifier[fromNow.type] {
+ type R = Deadline
+ def convert(d: FiniteDuration) = Deadline.now + d
+ }
+
+ implicit def intToDurationInt(n: Int) = new DurationInt(n)
+ implicit def longToDurationLong(n: Long) = new DurationLong(n)
+ implicit def doubleToDurationDouble(d: Double) = new DurationDouble(d)
+
+ implicit def pairIntToDuration(p: (Int, TimeUnit)) = Duration(p._1, p._2)
+ implicit def pairLongToDuration(p: (Long, TimeUnit)) = Duration(p._1, p._2)
+ implicit def durationToPair(d: Duration) = (d.length, d.unit)
+
+ /*
+ * Avoid reflection based invocation by using non-duck type
+ */
+ class IntMult(i: Int) {
+ def *(d: Duration) = d * i
+ }
+ implicit def intMult(i: Int) = new IntMult(i)
+
+ class LongMult(l: Long) {
+ def *(d: Duration) = d * l
+ }
+ implicit def longMult(l: Long) = new LongMult(l)
+
+ class DoubleMult(f: Double) {
+ def *(d: Duration) = d * f
+ }
+ implicit def doubleMult(f: Double) = new DoubleMult(f)
+}
+
+case class Deadline private (time: Duration) {
+ def +(other: Duration): Deadline = copy(time = time + other)
+ def -(other: Duration): Deadline = copy(time = time - other)
+ def -(other: Deadline): Duration = time - other.time
+ def timeLeft: Duration = this - Deadline.now
+ def hasTimeLeft(): Boolean = !isOverdue()
+ def isOverdue(): Boolean = (time.toNanos - System.nanoTime()) < 0
+}
+
+object Deadline {
+ def now: Deadline = Deadline(Duration(System.nanoTime, NANOSECONDS))
+}
+
+object Duration {
+ implicit def timeLeft(implicit d: Deadline): Duration = d.timeLeft
+
+ def apply(length: Long, unit: TimeUnit): FiniteDuration = new FiniteDuration(length, unit)
+ def apply(length: Double, unit: TimeUnit): FiniteDuration = fromNanos(unit.toNanos(1) * length)
+ def apply(length: Long, unit: String): FiniteDuration = {
+ val (mult, timeUnit) = Duration.timeUnit(unit)
+ new FiniteDuration(length * mult, timeUnit)
+ }
+
+ /**
+ * Construct a Duration by parsing a String. In case of a format error, a
+ * RuntimeException is thrown. See `unapply(String)` for more information.
+ */
+ def apply(s: String): Duration = unapply(s) getOrElse sys.error("format error " + s)
+
+ private val RE = ("""^\s*([\+|-]?\d+(?:\.\d+)?)\s*""" + // length part
+ "(?:" + // units are distinguished in separate match groups
+ "(d|day|days)|" +
+ "(h|hour|hours)|" +
+ "(min|minute|minutes)|" +
+ "(s|sec|second|seconds)|" +
+ "(ms|milli|millis|millisecond|milliseconds)|" +
+ "(µs|micro|micros|microsecond|microseconds)|" +
+ "(ns|nano|nanos|nanosecond|nanoseconds)" +
+ """)\s*$""").r // close the non-capturing group
+ private val REinf = """^\s*(?:\+|Plus)?Inf\s*$""".r
+ private val REminf = """^\s*(?:-|Minus)Inf\s*""".r
+
+ /**
+ * Deconstruct a Duration into `Long` length and [[java.util.concurrent.TimeUnit]] if it is a
+ * [[scala.util.concurrent.FiniteDuration]].
+ *
+ * @param d Duration to be deconstructed.
+ */
+ def unapply(d: Duration): Option[(Long, TimeUnit)] = {
+ if (d.finite_?) {
+ Some((d.length, d.unit))
+ } else {
+ None
+ }
+ }
+
+ /**
+ * Parse String, return None if no match. Format is `"<length><unit>"`, where
+ * whitespace is allowed before, between and after the parts. Infinities are
+ * designated by `"Inf"`, `"PlusInf"`, `"+Inf"` and `"-Inf"` or `"MinusInf"`.
+ */
+ def unapply(s: String): Option[Duration] = s match {
+ case RE(length, d, h, m, s, ms, mus, ns) ⇒
+ if (d ne null)
+ Some(Duration(JDouble.parseDouble(length) * 86400, SECONDS))
+ else if (h ne null)
+ Some(Duration(JDouble.parseDouble(length) * 3600, SECONDS))
+ else if (m ne null)
+ Some(Duration(JDouble.parseDouble(length) * 60, SECONDS))
+ else if (s ne null)
+ Some(Duration(JDouble.parseDouble(length), SECONDS))
+ else if (ms ne null)
+ Some(Duration(JDouble.parseDouble(length), MILLISECONDS))
+ else if (mus ne null)
+ Some(Duration(JDouble.parseDouble(length), MICROSECONDS))
+ else if (ns ne null)
+ Some(Duration(JDouble.parseDouble(length), NANOSECONDS))
+ else
+ sys.error("made some error in regex (should not be possible)")
+ case REinf() ⇒ Some(Inf)
+ case REminf() ⇒ Some(MinusInf)
+ case _ ⇒ None
+ }
+
+ def fromNanos(nanos: Double): FiniteDuration =
+ fromNanos((nanos + 0.5).asInstanceOf[Long])
+
+ def fromNanos(nanos: Long): FiniteDuration = {
+ if (nanos % 86400000000000L == 0) {
+ Duration(nanos / 1000000000L, SECONDS)
+ } else if (nanos % 1000000000L == 0) {
+ Duration(nanos / 1000000000L, SECONDS)
+ } else if (nanos % 1000000000L == 0) {
+ Duration(nanos / 1000000000L, SECONDS)
+ } else if (nanos % 1000000000L == 0) {
+ Duration(nanos / 1000000000L, SECONDS)
+ } else if (nanos % 1000000L == 0) {
+ Duration(nanos / 1000000L, MILLISECONDS)
+ } else if (nanos % 1000L == 0) {
+ Duration(nanos / 1000L, MICROSECONDS)
+ } else {
+ Duration(nanos, NANOSECONDS)
+ }
+ }
+
+ /**
+ * Parse TimeUnit from string representation.
+ */
+ protected[util] def timeUnit(unit: String): (Long, TimeUnit) = unit.toLowerCase match {
+ case "d" | "day" | "days" ⇒ (86400, SECONDS)
+ case "h" | "hour" | "hours" ⇒ (3600, SECONDS)
+ case "min" | "minute" | "minutes" ⇒ (60, SECONDS)
+ case "s" | "sec" | "second" | "seconds" ⇒ (1, SECONDS)
+ case "ms" | "milli" | "millis" | "millisecond" | "milliseconds" ⇒ (1, MILLISECONDS)
+ case "µs" | "micro" | "micros" | "microsecond" | "microseconds" ⇒ (1, MICROSECONDS)
+ case "ns" | "nano" | "nanos" | "nanosecond" | "nanoseconds" ⇒ (1, NANOSECONDS)
+ }
+
+ val Zero: FiniteDuration = new FiniteDuration(0, NANOSECONDS)
+ val Undefined: Duration = new Duration with Infinite {
+ override def toString = "Duration.Undefined"
+ override def equals(other: Any) = other.asInstanceOf[AnyRef] eq this
+ override def +(other: Duration): Duration = throw new IllegalArgumentException("cannot add Undefined duration")
+ override def -(other: Duration): Duration = throw new IllegalArgumentException("cannot subtract Undefined duration")
+ override def *(factor: Double): Duration = throw new IllegalArgumentException("cannot multiply Undefined duration")
+ override def /(factor: Double): Duration = throw new IllegalArgumentException("cannot divide Undefined duration")
+ override def /(other: Duration): Double = throw new IllegalArgumentException("cannot divide Undefined duration")
+ def compare(other: Duration) = throw new IllegalArgumentException("cannot compare Undefined duration")
+ def unary_- : Duration = throw new IllegalArgumentException("cannot negate Undefined duration")
+ }
+
+ trait Infinite {
+ this: Duration ⇒
+
+ def +(other: Duration): Duration =
+ other match {
+ case _: this.type ⇒ this
+ case _: Infinite ⇒ throw new IllegalArgumentException("illegal addition of infinities")
+ case _ ⇒ this
+ }
+ def -(other: Duration): Duration =
+ other match {
+ case _: this.type ⇒ throw new IllegalArgumentException("illegal subtraction of infinities")
+ case _ ⇒ this
+ }
+ def *(factor: Double): Duration = this
+ def /(factor: Double): Duration = this
+ def /(other: Duration): Double =
+ other match {
+ case _: Infinite ⇒ throw new IllegalArgumentException("illegal division of infinities")
+ // maybe questionable but pragmatic: Inf / 0 => Inf
+ case x ⇒ Double.PositiveInfinity * (if ((this > Zero) ^ (other >= Zero)) -1 else 1)
+ }
+
+ def finite_? = false
+
+ def length: Long = throw new IllegalArgumentException("length not allowed on infinite Durations")
+ def unit: TimeUnit = throw new IllegalArgumentException("unit not allowed on infinite Durations")
+ def toNanos: Long = throw new IllegalArgumentException("toNanos not allowed on infinite Durations")
+ def toMicros: Long = throw new IllegalArgumentException("toMicros not allowed on infinite Durations")
+ def toMillis: Long = throw new IllegalArgumentException("toMillis not allowed on infinite Durations")
+ def toSeconds: Long = throw new IllegalArgumentException("toSeconds not allowed on infinite Durations")
+ def toMinutes: Long = throw new IllegalArgumentException("toMinutes not allowed on infinite Durations")
+ def toHours: Long = throw new IllegalArgumentException("toHours not allowed on infinite Durations")
+ def toDays: Long = throw new IllegalArgumentException("toDays not allowed on infinite Durations")
+ def toUnit(unit: TimeUnit): Double = throw new IllegalArgumentException("toUnit not allowed on infinite Durations")
+
+ }
+
+ /**
+ * Infinite duration: greater than any other and not equal to any other,
+ * including itself.
+ */
+ val Inf: Duration = new Duration with Infinite {
+ override def toString = "Duration.Inf"
+ def compare(other: Duration) = if (other eq this) 0 else 1
+ def unary_- : Duration = MinusInf
+ }
+
+ /**
+ * Infinite negative duration: lesser than any other and not equal to any other,
+ * including itself.
+ */
+ val MinusInf: Duration = new Duration with Infinite {
+ override def toString = "Duration.MinusInf"
+ def compare(other: Duration) = if (other eq this) 0 else -1
+ def unary_- : Duration = Inf
+ }
+
+ // Java Factories
+ def create(length: Long, unit: TimeUnit): FiniteDuration = apply(length, unit)
+ def create(length: Double, unit: TimeUnit): FiniteDuration = apply(length, unit)
+ def create(length: Long, unit: String): FiniteDuration = apply(length, unit)
+ def parse(s: String): Duration = unapply(s).get
+
+ implicit object DurationIsOrdered extends Ordering[Duration] {
+ def compare(a: Duration, b: Duration) = a compare b
+ }
+}
+
+/**
+ * Utility for working with java.util.concurrent.TimeUnit durations.
+ *
+ * <p/>
+ * Examples:
+ * <pre>
+ * import scala.concurrent.util.Duration
+ * import java.util.concurrent.TimeUnit
+ *
+ * val duration = Duration(100, MILLISECONDS)
+ * val duration = Duration(100, "millis")
+ *
+ * duration.toNanos
+ * duration < 1.second
+ * duration <= Duration.Inf
+ * </pre>
+ *
+ * <p/>
+ * Implicits are also provided for Int, Long and Double. Example usage:
+ * <pre>
+ * import scala.concurrent.util.Duration._
+ *
+ * val duration = 100 millis
+ * </pre>
+ *
+ * Extractors, parsing and arithmetic are also included:
+ * <pre>
+ * val d = Duration("1.2 µs")
+ * val Duration(length, unit) = 5 millis
+ * val d2 = d * 2.5
+ * val d3 = d2 + 1.millisecond
+ * </pre>
+ */
+abstract class Duration extends Serializable with Ordered[Duration] {
+ def length: Long
+ def unit: TimeUnit
+ def toNanos: Long
+ def toMicros: Long
+ def toMillis: Long
+ def toSeconds: Long
+ def toMinutes: Long
+ def toHours: Long
+ def toDays: Long
+ def toUnit(unit: TimeUnit): Double
+
+ def +(other: Duration): Duration
+ def -(other: Duration): Duration
+ def *(factor: Double): Duration
+ def /(factor: Double): Duration
+ def /(other: Duration): Double
+ def unary_- : Duration
+ def finite_? : Boolean
+ def min(other: Duration): Duration = if (this < other) this else other
+ def max(other: Duration): Duration = if (this > other) this else other
+ def fromNow: Deadline = Deadline.now + this
+
+ // Java API
+ def lt(other: Duration) = this < other
+ def lteq(other: Duration) = this <= other
+ def gt(other: Duration) = this > other
+ def gteq(other: Duration) = this >= other
+ def plus(other: Duration) = this + other
+ def minus(other: Duration) = this - other
+ def mul(factor: Double) = this * factor
+ def div(factor: Double) = this / factor
+ def div(other: Duration) = this / other
+ def neg() = -this
+ def isFinite() = finite_?
+}
+
+object FiniteDuration {
+ implicit object FiniteDurationIsOrdered extends Ordering[FiniteDuration] {
+ def compare(a: FiniteDuration, b: FiniteDuration) = a compare b
+ }
+
+ def apply(length: Long, unit: TimeUnit) =
+ new FiniteDuration(length, unit)
+
+ def apply(length: Long, unit: String) = {
+ val (mult, timeUnit) = Duration.timeUnit(unit)
+ new FiniteDuration(length * mult, timeUnit)
+ }
+
+}
+
+class FiniteDuration(val length: Long, val unit: TimeUnit) extends Duration {
+ import Duration._
+
+ def toNanos = unit.toNanos(length)
+ def toMicros = unit.toMicros(length)
+ def toMillis = unit.toMillis(length)
+ def toSeconds = unit.toSeconds(length)
+ def toMinutes = unit.toMinutes(length)
+ def toHours = unit.toHours(length)
+ def toDays = unit.toDays(length)
+ def toUnit(u: TimeUnit) = long2double(toNanos) / NANOSECONDS.convert(1, u)
+
+ override def toString = this match {
+ case Duration(1, SECONDS) ⇒ "1 second"
+ case Duration(x, SECONDS) ⇒ x + " seconds"
+ case Duration(1, MILLISECONDS) ⇒ "1 millisecond"
+ case Duration(x, MILLISECONDS) ⇒ x + " milliseconds"
+ case Duration(1, MICROSECONDS) ⇒ "1 microsecond"
+ case Duration(x, MICROSECONDS) ⇒ x + " microseconds"
+ case Duration(1, NANOSECONDS) ⇒ "1 nanosecond"
+ case Duration(x, NANOSECONDS) ⇒ x + " nanoseconds"
+ }
+
+ def compare(other: Duration) =
+ if (other.finite_?) {
+ val me = toNanos
+ val o = other.toNanos
+ if (me > o) 1 else if (me < o) -1 else 0
+ } else -other.compare(this)
+
+ def +(other: Duration) = {
+ if (!other.finite_?) {
+ other
+ } else {
+ val nanos = toNanos + other.asInstanceOf[FiniteDuration].toNanos
+ fromNanos(nanos)
+ }
+ }
+
+ def -(other: Duration) = {
+ if (!other.finite_?) {
+ other
+ } else {
+ val nanos = toNanos - other.asInstanceOf[FiniteDuration].toNanos
+ fromNanos(nanos)
+ }
+ }
+
+ def *(factor: Double) = fromNanos(long2double(toNanos) * factor)
+
+ def /(factor: Double) = fromNanos(long2double(toNanos) / factor)
+
+ def /(other: Duration) = if (other.finite_?) long2double(toNanos) / other.toNanos else 0
+
+ def unary_- = Duration(-length, unit)
+
+ def finite_? = true
+
+ override def equals(other: Any) =
+ other.isInstanceOf[FiniteDuration] &&
+ toNanos == other.asInstanceOf[FiniteDuration].toNanos
+
+ override def hashCode = toNanos.asInstanceOf[Int]
+}
+
+class DurationInt(n: Int) {
+ import DurationImplicits.Classifier
+
+ def nanoseconds = Duration(n, NANOSECONDS)
+ def nanos = Duration(n, NANOSECONDS)
+ def nanosecond = Duration(n, NANOSECONDS)
+ def nano = Duration(n, NANOSECONDS)
+
+ def microseconds = Duration(n, MICROSECONDS)
+ def micros = Duration(n, MICROSECONDS)
+ def microsecond = Duration(n, MICROSECONDS)
+ def micro = Duration(n, MICROSECONDS)
+
+ def milliseconds = Duration(n, MILLISECONDS)
+ def millis = Duration(n, MILLISECONDS)
+ def millisecond = Duration(n, MILLISECONDS)
+ def milli = Duration(n, MILLISECONDS)
+
+ def seconds = Duration(n, SECONDS)
+ def second = Duration(n, SECONDS)
+
+ def minutes = Duration(n * 60, SECONDS)
+ def minute = Duration(n * 60, SECONDS)
+
+ def hours = Duration(n * 3600, SECONDS)
+ def hour = Duration(n * 3600, SECONDS)
+
+ def days = Duration(n * 86400, SECONDS)
+ def day = Duration(n * 86400, SECONDS)
+
+ def nanoseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS))
+ def nanos[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS))
+ def nanosecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS))
+ def nano[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS))
+
+ def microseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS))
+ def micros[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS))
+ def microsecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS))
+ def micro[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS))
+
+ def milliseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS))
+ def millis[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS))
+ def millisecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS))
+ def milli[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS))
+
+ def seconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, SECONDS))
+ def second[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, SECONDS))
+
+ def minutes[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n * 60, SECONDS))
+ def minute[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n * 60, SECONDS))
+
+ def hours[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n * 3600, SECONDS))
+ def hour[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n * 3600, SECONDS))
+
+ def days[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n * 86400, SECONDS))
+ def day[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n * 86400, SECONDS))
+}
+
+class DurationLong(n: Long) {
+ import DurationImplicits.Classifier
+
+ def nanoseconds = Duration(n, NANOSECONDS)
+ def nanos = Duration(n, NANOSECONDS)
+ def nanosecond = Duration(n, NANOSECONDS)
+ def nano = Duration(n, NANOSECONDS)
+
+ def microseconds = Duration(n, MICROSECONDS)
+ def micros = Duration(n, MICROSECONDS)
+ def microsecond = Duration(n, MICROSECONDS)
+ def micro = Duration(n, MICROSECONDS)
+
+ def milliseconds = Duration(n, MILLISECONDS)
+ def millis = Duration(n, MILLISECONDS)
+ def millisecond = Duration(n, MILLISECONDS)
+ def milli = Duration(n, MILLISECONDS)
+
+ def seconds = Duration(n, SECONDS)
+ def second = Duration(n, SECONDS)
+
+ def minutes = Duration(n * 60, SECONDS)
+ def minute = Duration(n * 60, SECONDS)
+
+ def hours = Duration(n * 3600, SECONDS)
+ def hour = Duration(n * 3600, SECONDS)
+
+ def days = Duration(n * 86400, SECONDS)
+ def day = Duration(n * 86400, SECONDS)
+
+ def nanoseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS))
+ def nanos[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS))
+ def nanosecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS))
+ def nano[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS))
+
+ def microseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS))
+ def micros[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS))
+ def microsecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS))
+ def micro[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS))
+
+ def milliseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS))
+ def millis[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS))
+ def millisecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS))
+ def milli[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS))
+
+ def seconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, SECONDS))
+ def second[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, SECONDS))
+
+ def minutes[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n * 60, SECONDS))
+ def minute[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n * 60, SECONDS))
+
+ def hours[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n * 3600, SECONDS))
+ def hour[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n * 3600, SECONDS))
+
+ def days[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n * 86400, SECONDS))
+ def day[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n * 86400, SECONDS))
+}
+
+class DurationDouble(d: Double) {
+ import DurationImplicits.Classifier
+
+ def nanoseconds = Duration(d, NANOSECONDS)
+ def nanos = Duration(d, NANOSECONDS)
+ def nanosecond = Duration(d, NANOSECONDS)
+ def nano = Duration(d, NANOSECONDS)
+
+ def microseconds = Duration(d, MICROSECONDS)
+ def micros = Duration(d, MICROSECONDS)
+ def microsecond = Duration(d, MICROSECONDS)
+ def micro = Duration(d, MICROSECONDS)
+
+ def milliseconds = Duration(d, MILLISECONDS)
+ def millis = Duration(d, MILLISECONDS)
+ def millisecond = Duration(d, MILLISECONDS)
+ def milli = Duration(d, MILLISECONDS)
+
+ def seconds = Duration(d, SECONDS)
+ def second = Duration(d, SECONDS)
+
+ def minutes = Duration(d * 60, SECONDS)
+ def minute = Duration(d * 60, SECONDS)
+
+ def hours = Duration(d * 3600, SECONDS)
+ def hour = Duration(d * 3600, SECONDS)
+
+ def days = Duration(d * 86400, SECONDS)
+ def day = Duration(d * 86400, SECONDS)
+
+ def nanoseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, NANOSECONDS))
+ def nanos[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, NANOSECONDS))
+ def nanosecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, NANOSECONDS))
+ def nano[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, NANOSECONDS))
+
+ def microseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MICROSECONDS))
+ def micros[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MICROSECONDS))
+ def microsecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MICROSECONDS))
+ def micro[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MICROSECONDS))
+
+ def milliseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MILLISECONDS))
+ def millis[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MILLISECONDS))
+ def millisecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MILLISECONDS))
+ def milli[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MILLISECONDS))
+
+ def seconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, SECONDS))
+ def second[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, SECONDS))
+
+ def minutes[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d * 60, SECONDS))
+ def minute[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d * 60, SECONDS))
+
+ def hours[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d * 3600, SECONDS))
+ def hour[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d * 3600, SECONDS))
+
+ def days[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d * 86400, SECONDS))
+ def day[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d * 86400, SECONDS))
+}
diff --git a/src/library/scala/reflect/api/Positions.scala b/src/library/scala/reflect/api/Positions.scala
index 181e7c1525..4c8c33bec8 100644
--- a/src/library/scala/reflect/api/Positions.scala
+++ b/src/library/scala/reflect/api/Positions.scala
@@ -1,9 +1,21 @@
package scala.reflect
package api
-trait Positions {
+trait Positions { self: Universe =>
+ /** TreeAnnotation is a generalisation of Position.
+ *
+ * TreeAnnotation cannot be an upperbound of Position since the corresponding classes
+ * must live outside of the universe for backwards compatibility (see scala.tools.nsc.util.Position).
+ * Thus, represent subtyping as coercions.
+ *
+ * Typically, positionToAnnotation is the identity, and annotationToPosition returns annot.pos
+ */
+ type TreeAnnotation // <: { def pos: Position }
+ val NoTreeAnnotation: TreeAnnotation
+ implicit def positionToAnnotation(pos: Position): TreeAnnotation // = pos
+ def annotationToPosition(annot: TreeAnnotation): Position // = annot.pos
+ def _checkSetAnnotation(tree: Tree, annot: TreeAnnotation): Unit = () // check that annot may overwrite tree.annot
- type Position
+ type Position // <: TreeAnnotation, but not practical to enforce this (would require moving Position, SourceFile, Reporter,... into the universe)
val NoPosition: Position
-
} \ No newline at end of file
diff --git a/src/library/scala/reflect/api/TreePrinters.scala b/src/library/scala/reflect/api/TreePrinters.scala
index 21b55e9c0e..43865915d3 100644
--- a/src/library/scala/reflect/api/TreePrinters.scala
+++ b/src/library/scala/reflect/api/TreePrinters.scala
@@ -41,7 +41,7 @@ trait TreePrinters { self: Universe =>
else if (tree.original != null)
print(".setOriginal(", tree.original, ")")
case tree: Tree =>
- print(tree.productPrefix+"(")
+ print(tree.printingPrefix+"(")
val it = tree.productIterator
while (it.hasNext) {
it.next() match {
diff --git a/src/library/scala/reflect/api/Trees.scala b/src/library/scala/reflect/api/Trees.scala
index a355207ff0..4ee13adf52 100644
--- a/src/library/scala/reflect/api/Trees.scala
+++ b/src/library/scala/reflect/api/Trees.scala
@@ -74,11 +74,24 @@ trait Trees { self: Universe =>
val id = nodeCount
nodeCount += 1
- private[this] var rawpos: Position = NoPosition
+ /** Prefix under which to print this tree type. Defaults to product
+ * prefix (e.g. DefTree) but because that is used in reification
+ * it cannot be altered without breaking reflection.
+ */
+ def printingPrefix = productPrefix
+
+ def pos: Position = annotationToPosition(rawannot)
+ def pos_=(pos: Position): Unit = annotation = pos
+ def setPos(newpos: Position): this.type = { pos = newpos; this }
+
+ private[this] var rawannot: TreeAnnotation = NoTreeAnnotation
+ def annotation: TreeAnnotation = rawannot
+ def annotation_=(annot: TreeAnnotation): Unit = {
+ _checkSetAnnotation(this, annot)
+ rawannot = annot
+ }
- def pos = rawpos
- def pos_=(pos: Position) = rawpos = pos
- def setPos(pos: Position): this.type = { rawpos = pos; this }
+ def setAnnotation(annot: TreeAnnotation): this.type = { annotation = annot; this }
private[this] var rawtpe: Type = _
@@ -159,11 +172,12 @@ trait Trees { self: Universe =>
def foreach(f: Tree => Unit) { new ForeachTreeTraverser(f).traverse(this) }
/** Find all subtrees matching predicate `p` */
- def filter(f: Tree => Boolean): List[Tree] = {
+ def withFilter(f: Tree => Boolean): List[Tree] = {
val ft = new FilterTreeTraverser(f)
ft.traverse(this)
ft.hits.toList
}
+ def filter(f: Tree => Boolean): List[Tree] = withFilter(f)
/** Returns optionally first tree (in a preorder traversal) which satisfies predicate `p`,
* or None if none exists.
@@ -216,7 +230,7 @@ trait Trees { self: Universe =>
duplicateTree(this).asInstanceOf[this.type]
private[scala] def copyAttrs(tree: Tree): this.type = {
- pos = tree.pos
+ annotation = tree.annotation
tpe = tree.tpe
if (hasSymbol) symbol = tree.symbol
this
@@ -249,6 +263,7 @@ trait Trees { self: Universe =>
* are in DefTrees.
*/
trait RefTree extends SymTree {
+ def qualifier: Tree // empty for Idents
def name: Name
}
@@ -489,16 +504,14 @@ trait Trees { self: Universe =>
/** Factory method for object creation `new tpt(args_1)...(args_n)`
* A `New(t, as)` is expanded to: `(new t).<init>(as)`
*/
- def New(tpt: Tree, argss: List[List[Tree]]): Tree = {
- // todo. we need to expose names in scala.reflect.api
- val superRef: Tree = Select(New(tpt), nme.CONSTRUCTOR)
- if (argss.isEmpty) Apply(superRef, Nil)
- else (superRef /: argss) (Apply)
+ def New(tpt: Tree, argss: List[List[Tree]]): Tree = argss match {
+ case Nil => new ApplyConstructor(tpt, Nil)
+ case xs :: rest => rest.foldLeft(new ApplyConstructor(tpt, xs): Tree)(Apply)
}
/** 0-1 argument list new, based on a type.
*/
def New(tpe: Type, args: Tree*): Tree =
- New(TypeTree(tpe), List(args.toList))
+ new ApplyConstructor(TypeTree(tpe), args.toList)
/** Type annotation, eliminated by explicit outer */
case class Typed(expr: Tree, tpt: Tree)
@@ -537,6 +550,10 @@ trait Trees { self: Universe =>
class ApplyImplicitView(fun: Tree, args: List[Tree]) extends Apply(fun, args)
+ class ApplyConstructor(tpt: Tree, args: List[Tree]) extends Apply(Select(New(tpt), nme.CONSTRUCTOR), args) {
+ override def printingPrefix = "ApplyConstructor"
+ }
+
/** Dynamic value application.
* In a dynamic application q.f(as)
* - q is stored in qual
@@ -575,7 +592,9 @@ trait Trees { self: Universe =>
Select(qualifier, sym.name) setSymbol sym
/** Identifier <name> */
- case class Ident(name: Name) extends RefTree
+ case class Ident(name: Name) extends RefTree {
+ def qualifier: Tree = EmptyTree
+ }
def Ident(name: String): Ident =
Ident(newTermName(name))
diff --git a/src/library/scala/runtime/AbstractPartialFunction.scala b/src/library/scala/runtime/AbstractPartialFunction.scala
index cbe778f09b..2e435d8a7e 100644
--- a/src/library/scala/runtime/AbstractPartialFunction.scala
+++ b/src/library/scala/runtime/AbstractPartialFunction.scala
@@ -8,45 +8,61 @@
package scala.runtime
-import scala.annotation.unchecked.uncheckedVariance
-
-/** This class provides a default implementation of partial functions
- * that is used for all partial function literals.
- * It contains an optimized `orElse` method which supports
- * chained `orElse` in linear time, and with no slow-down
- * if the `orElse` part is not needed.
- * The implementation of `orElse` works by cloning the abstract function object
- * and modifying a private `fallBack` variable that encodes the `getorElse` part.
+/** `AbstractPartialFunction` reformulates all operations of its supertrait `PartialFunction` in terms of `isDefinedAt` and `applyOrElse`.
+ *
+ * This allows more efficient implementations in many cases:
+ * - optimized `orElse` method supports chained `orElse` in linear time,
+ * and with no slow-down if the `orElse` part is not needed.
+ * - optimized `lift` method helps to avoid double evaluation of pattern matchers & guards
+ * of partial function literals.
+ *
+ * This trait is used as a basis for implementation of all partial function literals
+ * with non-exhaustive matchers.
+ *
+ * Use of `AbstractPartialFunction` instead of `PartialFunction` as a base trait for
+ * user-defined partial functions may result in better performance
+ * and more predictable behavior w.r.t. side effects.
+ *
+ * @author Pavel Pavlov
+ * @since 2.10
*/
-abstract class AbstractPartialFunction[-T1, +R]
- extends AbstractFunction1[T1, R]
- with PartialFunction[T1, R]
- with Cloneable {
-
- private var fallBackField: PartialFunction[T1 @uncheckedVariance, R @uncheckedVariance] = _
+abstract class AbstractPartialFunction[@specialized(scala.Int, scala.Long, scala.Float, scala.Double, scala.AnyRef) -T1, @specialized(scala.Unit, scala.Boolean, scala.Int, scala.Float, scala.Long, scala.Double, scala.AnyRef) +R] extends Function1[T1, R] with PartialFunction[T1, R] { self =>
+ // this method must be overridden for better performance,
+ // for backwards compatibility, fall back to the one inherited from PartialFunction
+ // this assumes the old-school partial functions override the apply method, though
+ // override def applyOrElse[A1 <: T1, B1 >: R](x: A1, default: A1 => B1): B1 = ???
- def fallBack: PartialFunction[T1, R] = synchronized {
- if (fallBackField eq null) fallBackField = PartialFunction.empty
- fallBackField
- }
+ // probably okay to make final since classes compiled before have overridden against the old version of AbstractPartialFunction
+ // let's not make it final so as not to confuse anyone
+ /*final*/ def apply(x: T1): R = applyOrElse(x, PartialFunction.empty)
- override protected def missingCase(x: T1): R = fallBack(x)
-
- // Question: Need to ensure that fallBack is overwritten before any access
- // Is the `synchronized` here the right thing to achieve this?
- // Is there a cheaper way?
- override def orElse[A1 <: T1, B1 >: R](that: PartialFunction[A1, B1]) : PartialFunction[A1, B1] = {
- val result = this.clone.asInstanceOf[AbstractPartialFunction[A1, B1]]
- result.synchronized {
- result.fallBackField = if (this.fallBackField eq null) that else this.fallBackField orElse that
- result
+ override final def andThen[C](k: R => C) : PartialFunction[T1, C] =
+ new AbstractPartialFunction[T1, C] {
+ def isDefinedAt(x: T1): Boolean = self.isDefinedAt(x)
+ override def applyOrElse[A1 <: T1, C1 >: C](x: A1, default: A1 => C1): C1 =
+ self.applyOrElse(x, PartialFunction.fallbackToken) match {
+ case PartialFunction.FallbackToken => default(x)
+ case z => k(z)
+ }
}
- }
-
- def isDefinedAt(x: T1): scala.Boolean = _isDefinedAt(x) || fallBack.isDefinedAt(x)
- def _isDefinedAt(x: T1): scala.Boolean
+ // TODO: remove
+ protected def missingCase(x: T1): R = throw new MatchError(x)
}
-
+/** `AbstractTotalFunction` is a partial function whose `isDefinedAt` method always returns `true`.
+ *
+ * This class is used as base class for partial function literals with
+ * certainly exhaustive pattern matchers.
+ *
+ * @author Pavel Pavlov
+ * @since 2.10
+ */
+abstract class AbstractTotalFunction[@specialized(scala.Int, scala.Long, scala.Float, scala.Double, scala.AnyRef) -T1, @specialized(scala.Unit, scala.Boolean, scala.Int, scala.Float, scala.Long, scala.Double, scala.AnyRef) +R] extends Function1[T1, R] with PartialFunction[T1, R] {
+ final def isDefinedAt(x: T1): Boolean = true
+ override final def applyOrElse[A1 <: T1, B1 >: R](x: A1, default: A1 => B1): B1 = apply(x)
+ override final def orElse[A1 <: T1, B1 >: R](that: PartialFunction[A1, B1]): PartialFunction[A1, B1] = this
+ //TODO: check generated code for PF literal here
+ override final def andThen[C](k: R => C): PartialFunction[T1, C] = { case x => k(apply(x)) }
+}
diff --git a/src/library/scala/testing/Show.scala b/src/library/scala/testing/Show.scala
index b0d094e466..7570bf705c 100644
--- a/src/library/scala/testing/Show.scala
+++ b/src/library/scala/testing/Show.scala
@@ -11,7 +11,7 @@
package scala.testing
/** Classes inheriting trait `Show` can test their member methods using the
- * notattion `meth(arg,,1,,, ..., arg,,n,,)`, where `meth` is the name of
+ * notation `meth(arg,,1,,, ..., arg,,n,,)`, where `meth` is the name of
* the method and `arg,,1,,,...,arg,,n,,` are the arguments.
*
* The only difference to a normal method call is the leading quote
diff --git a/src/library/scala/util/Duration.scala b/src/library/scala/util/Duration.scala
deleted file mode 100644
index 4c118f8b3b..0000000000
--- a/src/library/scala/util/Duration.scala
+++ /dev/null
@@ -1,485 +0,0 @@
-/**
- * Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
- */
-
-package scala.util
-
-import java.util.concurrent.TimeUnit
-import TimeUnit._
-import java.lang.{ Long ⇒ JLong, Double ⇒ JDouble }
-//import akka.actor.ActorSystem (commented methods)
-
-class TimerException(message: String) extends RuntimeException(message)
-
-/**
- * Simple timer class.
- * Usage:
- * <pre>
- * import akka.util.duration._
- * import akka.util.Timer
- *
- * val timer = Timer(30.seconds)
- * while (timer.isTicking) { ... }
- * </pre>
- */
-case class Timer(duration: Duration, throwExceptionOnTimeout: Boolean = false) {
- val startTimeInMillis = System.currentTimeMillis
- val timeoutInMillis = duration.toMillis
-
- /**
- * Returns true while the timer is ticking. After that it either throws and exception or
- * returns false. Depending on if the 'throwExceptionOnTimeout' argument is true or false.
- */
- def isTicking: Boolean = {
- if (!(timeoutInMillis > (System.currentTimeMillis - startTimeInMillis))) {
- if (throwExceptionOnTimeout) throw new TimerException("Time out after " + duration)
- else false
- } else true
- }
-}
-
-object Duration {
- def apply(length: Long, unit: TimeUnit): Duration = new FiniteDuration(length, unit)
- def apply(length: Double, unit: TimeUnit): Duration = fromNanos(unit.toNanos(1) * length)
- def apply(length: Long, unit: String): Duration = new FiniteDuration(length, timeUnit(unit))
-
- def fromNanos(nanos: Long): Duration = {
- if (nanos % 86400000000000L == 0) {
- Duration(nanos / 86400000000000L, DAYS)
- } else if (nanos % 3600000000000L == 0) {
- Duration(nanos / 3600000000000L, HOURS)
- } else if (nanos % 60000000000L == 0) {
- Duration(nanos / 60000000000L, MINUTES)
- } else if (nanos % 1000000000L == 0) {
- Duration(nanos / 1000000000L, SECONDS)
- } else if (nanos % 1000000L == 0) {
- Duration(nanos / 1000000L, MILLISECONDS)
- } else if (nanos % 1000L == 0) {
- Duration(nanos / 1000L, MICROSECONDS)
- } else {
- Duration(nanos, NANOSECONDS)
- }
- }
-
- def fromNanos(nanos: Double): Duration = fromNanos((nanos + 0.5).asInstanceOf[Long])
-
- /**
- * Construct a Duration by parsing a String. In case of a format error, a
- * RuntimeException is thrown. See `unapply(String)` for more information.
- */
- def apply(s: String): Duration = unapply(s) getOrElse sys.error("format error")
-
- /**
- * Deconstruct a Duration into length and unit if it is finite.
- */
- def unapply(d: Duration): Option[(Long, TimeUnit)] = {
- if (d.finite_?) {
- Some((d.length, d.unit))
- } else {
- None
- }
- }
-
- private val RE = ("""^\s*(\d+(?:\.\d+)?)\s*""" + // length part
- "(?:" + // units are distinguished in separate match groups
- "(d|day|days)|" +
- "(h|hour|hours)|" +
- "(min|minute|minutes)|" +
- "(s|sec|second|seconds)|" +
- "(ms|milli|millis|millisecond|milliseconds)|" +
- "(µs|micro|micros|microsecond|microseconds)|" +
- "(ns|nano|nanos|nanosecond|nanoseconds)" +
- """)\s*$""").r // close the non-capturing group
- private val REinf = """^\s*Inf\s*$""".r
- private val REminf = """^\s*(?:-\s*|Minus)Inf\s*""".r
-
- /**
- * Parse String, return None if no match. Format is `"<length><unit>"`, where
- * whitespace is allowed before, between and after the parts. Infinities are
- * designated by `"Inf"` and `"-Inf"` or `"MinusInf"`.
- */
- def unapply(s: String): Option[Duration] = s match {
- case RE(length, d, h, m, s, ms, mus, ns) ⇒
- if (d ne null) Some(Duration(JDouble.parseDouble(length), DAYS)) else if (h ne null) Some(Duration(JDouble.parseDouble(length), HOURS)) else if (m ne null) Some(Duration(JDouble.parseDouble(length), MINUTES)) else if (s ne null) Some(Duration(JDouble.parseDouble(length), SECONDS)) else if (ms ne null) Some(Duration(JDouble.parseDouble(length), MILLISECONDS)) else if (mus ne null) Some(Duration(JDouble.parseDouble(length), MICROSECONDS)) else if (ns ne null) Some(Duration(JDouble.parseDouble(length), NANOSECONDS)) else
- sys.error("made some error in regex (should not be possible)")
- case REinf() ⇒ Some(Inf)
- case REminf() ⇒ Some(MinusInf)
- case _ ⇒ None
- }
-
- /**
- * Parse TimeUnit from string representation.
- */
- def timeUnit(unit: String) = unit.toLowerCase match {
- case "d" | "day" | "days" ⇒ DAYS
- case "h" | "hour" | "hours" ⇒ HOURS
- case "min" | "minute" | "minutes" ⇒ MINUTES
- case "s" | "sec" | "second" | "seconds" ⇒ SECONDS
- case "ms" | "milli" | "millis" | "millisecond" | "milliseconds" ⇒ MILLISECONDS
- case "µs" | "micro" | "micros" | "microsecond" | "microseconds" ⇒ MICROSECONDS
- case "ns" | "nano" | "nanos" | "nanosecond" | "nanoseconds" ⇒ NANOSECONDS
- }
-
- val Zero: Duration = new FiniteDuration(0, NANOSECONDS)
- val Undefined: Duration = new Duration with Infinite {
- override def toString = "Duration.Undefined"
- override def equals(other: Any) = other.asInstanceOf[AnyRef] eq this
- override def +(other: Duration): Duration = throw new IllegalArgumentException("cannot add Undefined duration")
- override def -(other: Duration): Duration = throw new IllegalArgumentException("cannot subtract Undefined duration")
- override def *(factor: Double): Duration = throw new IllegalArgumentException("cannot multiply Undefined duration")
- override def /(factor: Double): Duration = throw new IllegalArgumentException("cannot divide Undefined duration")
- override def /(other: Duration): Double = throw new IllegalArgumentException("cannot divide Undefined duration")
- def >(other: Duration) = throw new IllegalArgumentException("cannot compare Undefined duration")
- def >=(other: Duration) = throw new IllegalArgumentException("cannot compare Undefined duration")
- def <(other: Duration) = throw new IllegalArgumentException("cannot compare Undefined duration")
- def <=(other: Duration) = throw new IllegalArgumentException("cannot compare Undefined duration")
- def unary_- : Duration = throw new IllegalArgumentException("cannot negate Undefined duration")
- }
-
- trait Infinite {
- this: Duration ⇒
-
- override def equals(other: Any) = false
-
- def +(other: Duration): Duration =
- other match {
- case _: this.type ⇒ this
- case _: Infinite ⇒ throw new IllegalArgumentException("illegal addition of infinities")
- case _ ⇒ this
- }
- def -(other: Duration): Duration =
- other match {
- case _: this.type ⇒ throw new IllegalArgumentException("illegal subtraction of infinities")
- case _ ⇒ this
- }
- def *(factor: Double): Duration = this
- def /(factor: Double): Duration = this
- def /(other: Duration): Double =
- other match {
- case _: Infinite ⇒ throw new IllegalArgumentException("illegal division of infinities")
- // maybe questionable but pragmatic: Inf / 0 => Inf
- case x ⇒ Double.PositiveInfinity * (if ((this > Zero) ^ (other >= Zero)) -1 else 1)
- }
-
- def finite_? = false
-
- def length: Long = throw new IllegalArgumentException("length not allowed on infinite Durations")
- def unit: TimeUnit = throw new IllegalArgumentException("unit not allowed on infinite Durations")
- def toNanos: Long = throw new IllegalArgumentException("toNanos not allowed on infinite Durations")
- def toMicros: Long = throw new IllegalArgumentException("toMicros not allowed on infinite Durations")
- def toMillis: Long = throw new IllegalArgumentException("toMillis not allowed on infinite Durations")
- def toSeconds: Long = throw new IllegalArgumentException("toSeconds not allowed on infinite Durations")
- def toMinutes: Long = throw new IllegalArgumentException("toMinutes not allowed on infinite Durations")
- def toHours: Long = throw new IllegalArgumentException("toHours not allowed on infinite Durations")
- def toDays: Long = throw new IllegalArgumentException("toDays not allowed on infinite Durations")
- def toUnit(unit: TimeUnit): Double = throw new IllegalArgumentException("toUnit not allowed on infinite Durations")
-
- def printHMS = toString
- }
-
- /**
- * Infinite duration: greater than any other and not equal to any other,
- * including itself.
- */
- val Inf: Duration = new Duration with Infinite {
- override def toString = "Duration.Inf"
- def >(other: Duration) = true
- def >=(other: Duration) = true
- def <(other: Duration) = false
- def <=(other: Duration) = false
- def unary_- : Duration = MinusInf
- }
-
- /**
- * Infinite negative duration: lesser than any other and not equal to any other,
- * including itself.
- */
- val MinusInf: Duration = new Duration with Infinite {
- override def toString = "Duration.MinusInf"
- def >(other: Duration) = false
- def >=(other: Duration) = false
- def <(other: Duration) = true
- def <=(other: Duration) = true
- def unary_- : Duration = Inf
- }
-
- // Java Factories
- def create(length: Long, unit: TimeUnit): Duration = apply(length, unit)
- def create(length: Double, unit: TimeUnit): Duration = apply(length, unit)
- def create(length: Long, unit: String): Duration = apply(length, unit)
- def parse(s: String): Duration = unapply(s).get
-}
-
-/**
- * Utility for working with java.util.concurrent.TimeUnit durations.
- *
- * <p/>
- * Examples of usage from Java:
- * <pre>
- * import akka.util.FiniteDuration;
- * import java.util.concurrent.TimeUnit;
- *
- * Duration duration = new FiniteDuration(100, MILLISECONDS);
- * Duration duration = new FiniteDuration(5, "seconds");
- *
- * duration.toNanos();
- * </pre>
- *
- * <p/>
- * Examples of usage from Scala:
- * <pre>
- * import akka.util.Duration
- * import java.util.concurrent.TimeUnit
- *
- * val duration = Duration(100, MILLISECONDS)
- * val duration = Duration(100, "millis")
- *
- * duration.toNanos
- * duration < 1.second
- * duration <= Duration.Inf
- * </pre>
- *
- * <p/>
- * Implicits are also provided for Int, Long and Double. Example usage:
- * <pre>
- * import akka.util.duration._
- *
- * val duration = 100 millis
- * </pre>
- *
- * Extractors, parsing and arithmetic are also included:
- * <pre>
- * val d = Duration("1.2 µs")
- * val Duration(length, unit) = 5 millis
- * val d2 = d * 2.5
- * val d3 = d2 + 1.millisecond
- * </pre>
- */
-abstract class Duration extends Serializable {
- def length: Long
- def unit: TimeUnit
- def toNanos: Long
- def toMicros: Long
- def toMillis: Long
- def toSeconds: Long
- def toMinutes: Long
- def toHours: Long
- def toDays: Long
- def toUnit(unit: TimeUnit): Double
- def printHMS: String
- def <(other: Duration): Boolean
- def <=(other: Duration): Boolean
- def >(other: Duration): Boolean
- def >=(other: Duration): Boolean
- def +(other: Duration): Duration
- def -(other: Duration): Duration
- def *(factor: Double): Duration
- def /(factor: Double): Duration
- def /(other: Duration): Double
- def unary_- : Duration
- def finite_? : Boolean
-// def dilated(implicit system: ActorSystem): Duration = this * system.settings.TestTimeFactor
- def min(other: Duration): Duration = if (this < other) this else other
- def max(other: Duration): Duration = if (this > other) this else other
- def sleep(): Unit = Thread.sleep(toMillis)
-
- // Java API
- def lt(other: Duration) = this < other
- def lteq(other: Duration) = this <= other
- def gt(other: Duration) = this > other
- def gteq(other: Duration) = this >= other
- def plus(other: Duration) = this + other
- def minus(other: Duration) = this - other
- def mul(factor: Double) = this * factor
- def div(factor: Double) = this / factor
- def div(other: Duration) = this / other
- def neg() = -this
- def isFinite() = finite_?
-}
-
-class FiniteDuration(val length: Long, val unit: TimeUnit) extends Duration {
- import Duration._
-
- def this(length: Long, unit: String) = this(length, Duration.timeUnit(unit))
-
- def toNanos = unit.toNanos(length)
- def toMicros = unit.toMicros(length)
- def toMillis = unit.toMillis(length)
- def toSeconds = unit.toSeconds(length)
- def toMinutes = unit.toMinutes(length)
- def toHours = unit.toHours(length)
- def toDays = unit.toDays(length)
- def toUnit(u: TimeUnit) = long2double(toNanos) / NANOSECONDS.convert(1, u)
-
- override def toString = this match {
- case Duration(1, DAYS) ⇒ "1 day"
- case Duration(x, DAYS) ⇒ x + " days"
- case Duration(1, HOURS) ⇒ "1 hour"
- case Duration(x, HOURS) ⇒ x + " hours"
- case Duration(1, MINUTES) ⇒ "1 minute"
- case Duration(x, MINUTES) ⇒ x + " minutes"
- case Duration(1, SECONDS) ⇒ "1 second"
- case Duration(x, SECONDS) ⇒ x + " seconds"
- case Duration(1, MILLISECONDS) ⇒ "1 millisecond"
- case Duration(x, MILLISECONDS) ⇒ x + " milliseconds"
- case Duration(1, MICROSECONDS) ⇒ "1 microsecond"
- case Duration(x, MICROSECONDS) ⇒ x + " microseconds"
- case Duration(1, NANOSECONDS) ⇒ "1 nanosecond"
- case Duration(x, NANOSECONDS) ⇒ x + " nanoseconds"
- }
-
- def printHMS = "%02d:%02d:%06.3f".format(toHours, toMinutes % 60, toMillis / 1000.0 % 60)
-
- def <(other: Duration) = {
- if (other.finite_?) {
- toNanos < other.asInstanceOf[FiniteDuration].toNanos
- } else {
- other > this
- }
- }
-
- def <=(other: Duration) = {
- if (other.finite_?) {
- toNanos <= other.asInstanceOf[FiniteDuration].toNanos
- } else {
- other >= this
- }
- }
-
- def >(other: Duration) = {
- if (other.finite_?) {
- toNanos > other.asInstanceOf[FiniteDuration].toNanos
- } else {
- other < this
- }
- }
-
- def >=(other: Duration) = {
- if (other.finite_?) {
- toNanos >= other.asInstanceOf[FiniteDuration].toNanos
- } else {
- other <= this
- }
- }
-
- def +(other: Duration) = {
- if (!other.finite_?) {
- other
- } else {
- val nanos = toNanos + other.asInstanceOf[FiniteDuration].toNanos
- fromNanos(nanos)
- }
- }
-
- def -(other: Duration) = {
- if (!other.finite_?) {
- other
- } else {
- val nanos = toNanos - other.asInstanceOf[FiniteDuration].toNanos
- fromNanos(nanos)
- }
- }
-
- def *(factor: Double) = fromNanos(long2double(toNanos) * factor)
-
- def /(factor: Double) = fromNanos(long2double(toNanos) / factor)
-
- def /(other: Duration) = if (other.finite_?) long2double(toNanos) / other.toNanos else 0
-
- def unary_- = Duration(-length, unit)
-
- def finite_? = true
-
- override def equals(other: Any) =
- other.isInstanceOf[FiniteDuration] &&
- toNanos == other.asInstanceOf[FiniteDuration].toNanos
-
- override def hashCode = toNanos.asInstanceOf[Int]
-}
-
-class DurationInt(n: Int) {
- def nanoseconds = Duration(n, NANOSECONDS)
- def nanos = Duration(n, NANOSECONDS)
- def nanosecond = Duration(n, NANOSECONDS)
- def nano = Duration(n, NANOSECONDS)
-
- def microseconds = Duration(n, MICROSECONDS)
- def micros = Duration(n, MICROSECONDS)
- def microsecond = Duration(n, MICROSECONDS)
- def micro = Duration(n, MICROSECONDS)
-
- def milliseconds = Duration(n, MILLISECONDS)
- def millis = Duration(n, MILLISECONDS)
- def millisecond = Duration(n, MILLISECONDS)
- def milli = Duration(n, MILLISECONDS)
-
- def seconds = Duration(n, SECONDS)
- def second = Duration(n, SECONDS)
-
- def minutes = Duration(n, MINUTES)
- def minute = Duration(n, MINUTES)
-
- def hours = Duration(n, HOURS)
- def hour = Duration(n, HOURS)
-
- def days = Duration(n, DAYS)
- def day = Duration(n, DAYS)
-}
-
-class DurationLong(n: Long) {
- def nanoseconds = Duration(n, NANOSECONDS)
- def nanos = Duration(n, NANOSECONDS)
- def nanosecond = Duration(n, NANOSECONDS)
- def nano = Duration(n, NANOSECONDS)
-
- def microseconds = Duration(n, MICROSECONDS)
- def micros = Duration(n, MICROSECONDS)
- def microsecond = Duration(n, MICROSECONDS)
- def micro = Duration(n, MICROSECONDS)
-
- def milliseconds = Duration(n, MILLISECONDS)
- def millis = Duration(n, MILLISECONDS)
- def millisecond = Duration(n, MILLISECONDS)
- def milli = Duration(n, MILLISECONDS)
-
- def seconds = Duration(n, SECONDS)
- def second = Duration(n, SECONDS)
-
- def minutes = Duration(n, MINUTES)
- def minute = Duration(n, MINUTES)
-
- def hours = Duration(n, HOURS)
- def hour = Duration(n, HOURS)
-
- def days = Duration(n, DAYS)
- def day = Duration(n, DAYS)
-}
-
-class DurationDouble(d: Double) {
- def nanoseconds = Duration(d, NANOSECONDS)
- def nanos = Duration(d, NANOSECONDS)
- def nanosecond = Duration(d, NANOSECONDS)
- def nano = Duration(d, NANOSECONDS)
-
- def microseconds = Duration(d, MICROSECONDS)
- def micros = Duration(d, MICROSECONDS)
- def microsecond = Duration(d, MICROSECONDS)
- def micro = Duration(d, MICROSECONDS)
-
- def milliseconds = Duration(d, MILLISECONDS)
- def millis = Duration(d, MILLISECONDS)
- def millisecond = Duration(d, MILLISECONDS)
- def milli = Duration(d, MILLISECONDS)
-
- def seconds = Duration(d, SECONDS)
- def second = Duration(d, SECONDS)
-
- def minutes = Duration(d, MINUTES)
- def minute = Duration(d, MINUTES)
-
- def hours = Duration(d, HOURS)
- def hour = Duration(d, HOURS)
-
- def days = Duration(d, DAYS)
- def day = Duration(d, DAYS)
-}
diff --git a/src/library/scala/util/Timeout.scala b/src/library/scala/util/Timeout.scala
deleted file mode 100644
index 0190675344..0000000000
--- a/src/library/scala/util/Timeout.scala
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
- */
-package scala.util
-
-import java.util.concurrent.TimeUnit
-
-case class Timeout(duration: Duration) {
- def this(timeout: Long) = this(Duration(timeout, TimeUnit.MILLISECONDS))
- def this(length: Long, unit: TimeUnit) = this(Duration(length, unit))
-}
-
-object Timeout {
- /**
- * A timeout with zero duration, will cause most requests to always timeout.
- */
- val zero = new Timeout(Duration.Zero)
-
- /**
- * A Timeout with infinite duration. Will never timeout. Use extreme caution with this
- * as it may cause memory leaks, blocked threads, or may not even be supported by
- * the receiver, which would result in an exception.
- */
- val never = new Timeout(Duration.Inf)
-
- def apply(timeout: Long) = new Timeout(timeout)
- def apply(length: Long, unit: TimeUnit) = new Timeout(length, unit)
-
- implicit def durationToTimeout(duration: Duration) = new Timeout(duration)
- implicit def intToTimeout(timeout: Int) = new Timeout(timeout)
- implicit def longToTimeout(timeout: Long) = new Timeout(timeout)
- //implicit def defaultTimeout(implicit system: ActorSystem) = system.settings.ActorTimeout (have to introduce this in ActorSystem)
-}
diff --git a/src/library/scala/util/control/Exception.scala b/src/library/scala/util/control/Exception.scala
index 5e3f8b6451..20a179a884 100644
--- a/src/library/scala/util/control/Exception.scala
+++ b/src/library/scala/util/control/Exception.scala
@@ -230,8 +230,5 @@ object Exception {
classes exists (_ isAssignableFrom x.getClass)
private def pfFromExceptions(exceptions: Class[_]*): PartialFunction[Throwable, Nothing] =
- new scala.runtime.AbstractPartialFunction[Throwable, Nothing] {
- def apply(x: Throwable) = throw x
- def _isDefinedAt(x: Throwable) = wouldMatch(x, exceptions)
- }
+ { case x if wouldMatch(x, exceptions) => throw x }
}
diff --git a/src/library/scala/util/matching/Regex.scala b/src/library/scala/util/matching/Regex.scala
index ca97515e23..3f21cc9724 100644
--- a/src/library/scala/util/matching/Regex.scala
+++ b/src/library/scala/util/matching/Regex.scala
@@ -133,6 +133,15 @@ import java.util.regex.{ Pattern, Matcher }
*
* @param regex A string representing a regular expression
* @param groupNames A mapping from names to indices in capture groups
+ *
+ * @define replacementString
+ * In the replacement String, a dollar sign (`$`) followed by a number will be
+ * interpreted as a reference to a group in the matched pattern, with numbers
+ * 1 through 9 corresponding to the first nine groups, and 0 standing for the
+ * whole match. Any other character is an error. The backslash (`\`) character
+ * will be interpreted as an escape character, and can be used to escape the
+ * dollar sign. One can use [[scala.util.matching.Regex]]'s `quoteReplacement`
+ * to automatically escape these characters.
*/
@SerialVersionUID(-2094783597747625537L)
class Regex(regex: String, groupNames: String*) extends Serializable {
@@ -180,7 +189,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable {
None
}
- /** Return all matches of this regexp in given character sequence as a [[scala.util.mathcing.Regex.MatchIterator]],
+ /** Return all matches of this regexp in given character sequence as a [[scala.util.matching.Regex.MatchIterator]],
* which is a special [[scala.collection.Iterator]] that returns the
* matched strings, but can also be converted into a normal iterator
* that returns objects of type [[scala.util.matching.Regex.Match]]
@@ -193,6 +202,25 @@ class Regex(regex: String, groupNames: String*) extends Serializable {
*/
def findAllIn(source: java.lang.CharSequence) = new Regex.MatchIterator(source, this, groupNames)
+
+ /** Return all matches of this regexp in given character sequence as a
+ * [[scala.collection.Iterator]] of [[scala.util.matching.Regex.Match].
+ *
+ * @param source The text to match against.
+ * @return A [[scala.collection.Iterator]] of [[scala.util.matching.Regex.Match]] for all matches.
+ * @example {{{for (words <- """\w+""".r findAllMatchIn "A simple example.") yield words.start}}}
+ */
+ def findAllMatchIn(source: java.lang.CharSequence): Iterator[Match] = {
+ val matchIterator = findAllIn(source)
+ new Iterator[Match] {
+ def hasNext = matchIterator.hasNext
+ def next: Match = {
+ matchIterator.next;
+ new Match(matchIterator.source, matchIterator.matcher, matchIterator.groupNames).force
+ }
+ }
+ }
+
/** Return optionally first matching string of this regexp in given character sequence,
* or None if it does not exist.
*
@@ -258,6 +286,8 @@ class Regex(regex: String, groupNames: String*) extends Serializable {
/** Replaces all matches by a string.
*
+ * $replacementString
+ *
* @param target The string to match
* @param replacement The string that will replace each match
* @return The resulting string
@@ -280,6 +310,8 @@ class Regex(regex: String, groupNames: String*) extends Serializable {
* val repl = datePattern replaceAllIn (text, m => m.group("month")+"/"+m.group("day"))
* }}}
*
+ * $replacementString
+ *
* @param target The string to match.
* @param replacer The function which maps a match to another string.
* @return The target string after replacements.
@@ -298,13 +330,15 @@ class Regex(regex: String, groupNames: String*) extends Serializable {
* {{{
* import scala.util.matching.Regex._
*
- * val map = Map("x" -> "a var", "y" -> "another var")
+ * val map = Map("x" -> "a var", "y" -> """some $ and \ signs""")
* val text = "A text with variables %x, %y and %z."
* val varPattern = """%(\w+)""".r
- * val mapper = (m: Match) => map get (m group 1)
+ * val mapper = (m: Match) => map get (m group 1) map (quoteReplacement(_))
* val repl = varPattern replaceSomeIn (text, mapper)
* }}}
*
+ * $replacementString
+ *
* @param target The string to match.
* @param replacer The function which optionally maps a match to another string.
* @return The target string after replacements.
@@ -319,6 +353,8 @@ class Regex(regex: String, groupNames: String*) extends Serializable {
/** Replaces the first match by a string.
*
+ * $replacementString
+ *
* @param target The string to match
* @param replacement The string that will replace the match
* @return The resulting string
@@ -505,7 +541,7 @@ object Regex {
class MatchIterator(val source: java.lang.CharSequence, val regex: Regex, val groupNames: Seq[String])
extends AbstractIterator[String] with Iterator[String] with MatchData { self =>
- protected val matcher = regex.pattern.matcher(source)
+ protected[Regex] val matcher = regex.pattern.matcher(source)
private var nextSeen = false
/** Is there another match? */
@@ -569,4 +605,18 @@ object Regex {
def replace(rs: String) = matcher.appendReplacement(sb, rs)
}
+
+ /** Quotes replacement strings to be used in replacement methods.
+ *
+ * Replacement methods give special meaning to backslashes (`\`) and
+ * dollar signs (`$`) in replacement strings, so they are not treated
+ * as literals. This method escapes these characters so the resulting
+ * string can be used as a literal replacement representing the input
+ * string.
+ *
+ * @param text The string one wishes to use as literal replacement.
+ * @return A string that can be used to replace matches with `text`.
+ * @example {{{"CURRENCY".r.replaceAllIn(input, Regex quoteReplacement "US$")}}}
+ */
+ def quoteReplacement(text: String): String = Matcher quoteReplacement text
}
diff --git a/src/library/scala/xml/Elem.scala b/src/library/scala/xml/Elem.scala
index cc244a5b88..5b6b9f2bb9 100755
--- a/src/library/scala/xml/Elem.scala
+++ b/src/library/scala/xml/Elem.scala
@@ -23,12 +23,12 @@ object Elem {
* @deprecated This factory method is retained for backward compatibility; please use the other one, with which you
* can specify your own preference for minimizeEmpty.
*/
- @deprecated
- def apply(prefix: String,label: String, attributes: MetaData, scope: NamespaceBinding, child: Node*): Elem =
+ @deprecated("Use the other apply method in this object", "2.10.0")
+ def apply(prefix: String, label: String, attributes: MetaData, scope: NamespaceBinding, child: Node*): Elem =
apply(prefix, label, attributes, scope, child.isEmpty, child: _*)
- def apply(prefix: String,label: String, attributes: MetaData, scope: NamespaceBinding, minimizeEmpty: Boolean, child: Node*): Elem =
- new Elem(prefix,label,attributes,scope, minimizeEmpty, child:_*)
+ def apply(prefix: String, label: String, attributes: MetaData, scope: NamespaceBinding, minimizeEmpty: Boolean, child: Node*): Elem =
+ new Elem(prefix, label, attributes, scope, minimizeEmpty, child: _*)
def unapplySeq(n: Node) = n match {
case _: SpecialNode | _: Group => None
diff --git a/src/library/scala/xml/XML.scala b/src/library/scala/xml/XML.scala
index 4beba91899..f6955c6612 100755
--- a/src/library/scala/xml/XML.scala
+++ b/src/library/scala/xml/XML.scala
@@ -15,8 +15,7 @@ import java.io.{ InputStream, Reader, StringReader, Writer }
import java.nio.channels.Channels
import scala.util.control.Exception.ultimately
-object Source
-{
+object Source {
def fromFile(file: File) = new InputSource(new FileInputStream(file))
def fromFile(fd: FileDescriptor) = new InputSource(new FileInputStream(fd))
def fromFile(name: String) = new InputSource(new FileInputStream(name))
@@ -31,13 +30,18 @@ object Source
* Governs how empty elements (i.e. those without child elements) should be serialized.
*/
object MinimizeMode extends Enumeration {
- /** Minimize empty tags if they were originally empty when parsed, or if they were constructed with [[scala.xml.Elem]]`#minimizeEmpty` == true */
+ /** Minimize empty tags if they were originally empty when parsed, or if they were constructed
+ * with [[scala.xml.Elem]]`#minimizeEmpty` == true
+ */
val Default = Value
- /** Always minimize empty tags. Note that this may be problematic for XHTML, in which case [[scala.xml.Xhtml]]`#toXhtml` should be used instead. */
+ /** Always minimize empty tags. Note that this may be problematic for XHTML, in which
+ * case [[scala.xml.Xhtml]]`#toXhtml` should be used instead.
+ */
val Always = Value
- /** Never minimize empty tags. */
+ /** Never minimize empty tags.
+ */
val Never = Value
}
@@ -50,8 +54,7 @@ import Source._
* @author Burak Emir
* @version 1.0, 25/04/2005
*/
-object XML extends XMLLoader[Elem]
-{
+object XML extends XMLLoader[Elem] {
val xml = "xml"
val xmlns = "xmlns"
val namespace = "http://www.w3.org/XML/1998/namespace"
diff --git a/src/library/scala/xml/factory/LoggedNodeFactory.scala b/src/library/scala/xml/factory/LoggedNodeFactory.scala
index c15a9ebe7b..abf8f97f03 100644
--- a/src/library/scala/xml/factory/LoggedNodeFactory.scala
+++ b/src/library/scala/xml/factory/LoggedNodeFactory.scala
@@ -18,7 +18,7 @@ object testLogged extends Application {
with scala.util.logging.ConsoleLogger
Console.println("Start")
- val doc = x.load(new java.net.URL("http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk/build.xml"))
+ val doc = x.load(new java.net.URL("http://example.com/file.xml"))
Console.println("End")
Console.println(doc)
}
diff --git a/src/library/scala/xml/parsing/MarkupParser.scala b/src/library/scala/xml/parsing/MarkupParser.scala
index 32feaa2209..af9b5f47cf 100755
--- a/src/library/scala/xml/parsing/MarkupParser.scala
+++ b/src/library/scala/xml/parsing/MarkupParser.scala
@@ -134,7 +134,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests
//
/** {{{
- * &lt;? prolog ::= xml S ... ?&gt;
+ * <? prolog ::= xml S ... ?>
* }}} */
def xmlProcInstr(): MetaData = {
xToken("xml")
@@ -195,7 +195,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests
}
/** {{{
- * &lt;? prolog ::= xml S?
+ * <? prolog ::= xml S?
* // this is a bit more lenient than necessary...
* }}} */
def prolog(): (Option[String], Option[String], Option[Boolean]) =
@@ -355,7 +355,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests
}
/** {{{
- * '&lt;! CharData ::= [CDATA[ ( {char} - {char}"]]&gt;"{char} ) ']]&gt;'
+ * '<! CharData ::= [CDATA[ ( {char} - {char}"]]>"{char} ) ']]>'
*
* see [15]
* }}} */
@@ -369,7 +369,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests
}
/** {{{
- * Comment ::= '&lt;!--' ((Char - '-') | ('-' (Char - '-')))* '--&gt;'
+ * Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
*
* see [15]
* }}} */
@@ -399,7 +399,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests
}
/** {{{
- * '&lt;' content1 ::= ...
+ * '<' content1 ::= ...
* }}} */
def content1(pscope: NamespaceBinding, ts: NodeBuffer) {
ch match {
@@ -420,7 +420,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests
}
/** {{{
- * content1 ::= '&lt;' content1 | '&amp;' charref ...
+ * content1 ::= '<' content1 | '&' charref ...
* }}} */
def content(pscope: NamespaceBinding): NodeSeq = {
var ts = new NodeBuffer
@@ -490,7 +490,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests
/** parses document type declaration and assigns it to instance variable
* dtd.
* {{{
- * &lt;! parseDTD ::= DOCTYPE name ... >
+ * <! parseDTD ::= DOCTYPE name ... >
* }}} */
def parseDTD() { // dirty but fast
var extID: ExternalID = null
@@ -545,8 +545,8 @@ trait MarkupParser extends MarkupParserCommon with TokenTests
}
/** {{{
- * '&lt;' element ::= xmlTag1 '&gt;' { xmlExpr | '{' simpleExpr '}' } ETag
- * | xmlTag1 '/' '&gt;'
+ * '<' element ::= xmlTag1 '>' { xmlExpr | '{' simpleExpr '}' } ETag
+ * | xmlTag1 '/' '>'
* }}} */
def element1(pscope: NamespaceBinding): NodeSeq = {
val pos = this.pos
@@ -778,7 +778,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests
}
/** {{{
- * &lt;! attlist := ATTLIST
+ * <! attlist := ATTLIST
* }}} */
def attrDecl() = {
xToken("TTLIST")
@@ -824,7 +824,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests
}
/** {{{
- * &lt;! element := ELEMENT
+ * <! element := ELEMENT
* }}} */
def entityDecl() = {
var isParameterEntity = false
diff --git a/src/manual/scala/man1/fsc.scala b/src/manual/scala/man1/fsc.scala
index 1f82cdf0ce..2aafe7d82c 100644
--- a/src/manual/scala/man1/fsc.scala
+++ b/src/manual/scala/man1/fsc.scala
@@ -141,7 +141,6 @@ object fsc extends Command {
val seeAlso = Section("SEE ALSO",
- Link(Bold("sbaz") & "(1)", "sbaz.html") & ", " &
Link(Bold("scala") & "(1)", "scala.html") & ", " &
Link(Bold("scalac") & "(1)", "scalac.html") & ", " &
Link(Bold("scaladoc") & "(1)", "scaladoc.html") & ", " &
@@ -149,9 +148,9 @@ object fsc extends Command {
def manpage = new Document {
title = command
- date = "January 2007"
+ date = "March 2012"
author = "Lex Spoon"
- version = "0.4"
+ version = "0.5"
sections = List(
name,
synopsis,
diff --git a/src/manual/scala/man1/sbaz.scala b/src/manual/scala/man1/sbaz.scala
deleted file mode 100644
index 2e12330408..0000000000
--- a/src/manual/scala/man1/sbaz.scala
+++ /dev/null
@@ -1,209 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2011 LAMP/EPFL
- * @author Stephane Micheloud
- */
-
-package scala.man1
-
-/**
- * @author Stephane Micheloud
- * @version 1.0
- */
-object sbaz extends Command {
- import _root_.scala.tools.docutil.ManPage._
-
- protected val cn = new Error().getStackTrace()(0).getClassName()
-
- val name = Section("NAME",
-
- MBold(command) & " " & NDash & " Scala package sharing tool for the " &
- Link("Scala 2", "http://scala-lang.org/") & " language")
-
- val synopsis = Section("SYNOPSIS",
-
- CmdLine(" [ " & Argument("global_options") & " ] " & Argument("command") &
- " [ " & Argument("command_options") & " ]"))
-
- val parameters = Section("PARAMETERS",
-
- DefinitionList(
- Definition(
- Mono(Argument("global_options")),
- "Command line options. See " & Link(Bold("OPTIONS"), "#options") &
- " below."),
- Definition(
- Mono(Argument("command")),
- "Internal " & MBold(command) & " command."),
- Definition(
- Mono(Argument("command_options")),
- MBold(command) & " command options.")))
-
- val description = Section("DESCRIPTION",
-
- "The " & MBold(command) & " tool is a system used by Scala enthusiasts " &
- "to share computer files with each other. In particular, it makes it " &
- "easy to share libraries and applications.")
-
- val options = Section("OPTIONS",
-
- "The " & MBold(command) & " tool has a set of standard options that are " &
- "supported on the current development environment and will be supported " &
- "in future releases.",
-
- Section("Global Options",
- DefinitionList(
- Definition(
- CmdOption("d", Argument("dir")),
- "Operate on dir as the local managed directory."),
- Definition(
- CmdOption("n") & "| " & CmdOptionLong("dryrun"),
- "Do not actually do anything. Only print out what " +
- "tool would normally do with the following arguments."),
- Definition(
- CmdOption("v") & "| " & CmdOptionLong("verbose"),
- "Output messages about what the " & MBold(command) & " tool is doing"),
- Definition(
- CmdOption("version"),
- "Display the version information"),
-
- Definition(
- CmdOptionLong("univ", Argument("name")),
- "Operate on the named remote universe, selected from those " &
- "in the local managed directory's universe. Affects "&
- "the "&MBold("share")&" and "&MBold("retract")&" commands."),
-
- Definition(
- CmdOptionLong("univ-url", Argument("url")),
- "Operate on the universe at the specified URL. Affects "&
- "the "&MBold("share")&" and "&MBold("retract")&" commands."))),
-
- Section("Available Commands",
- DefinitionList(
- Definition(
- MBold("available"),
- "List the available packages for installation; only display the " +
- "three most recent versions of each package."),
- Definition(
- MBold("available") & " " & CmdOption("a"),
- "List the available packages for installation; display all shared " +
- "versions of each package."),
- Definition(
- MBold("compact"),
- "Clear the download cache to save space."),
- Definition(
- MBold("help"),
- "Display a help message."),
- Definition(
- MBold("install"),
- "Install a package."),
- Definition(
- MBold("installed"),
- "List the packages that are installed."),
- Definition(
- MBold("keycreate"),
- "Request that a new key be created."),
- Definition(
- MBold("keyforget"),
- "Forget the specified key."),
- Definition(
- MBold("keyknown"),
- "List all known keys."),
- Definition(
- MBold("keyremember"),
- "Remember the specified key for future use."),
- Definition(
- MBold("keyremoteknown"),
- "List all keys known to the bazaar server."),
- Definition(
- MBold("keyrevoke"),
- "Request that a specified key be revoked."),
- Definition(
- MBold("pack") & " " & Argument("name") & " " & Argument("directory") &
- " [ " & Argument("options") & " ]",
- "Create an sbaz package and, if a link base is specified, "&
- "an advertisement file. The package file is named " &
- Mono("name-version.sbp") & ". The advertisement file is named " &
- Mono("name-version.advert") & ". The URL is the advertisement " &
- "file is the URL base with the package filename appended."),
- Definition(
- MBold("remove"),
- "Remove a package."),
- Definition(
- MBold("retract"),
- "Retract a previously shared package."),
- Definition(
- MBold("setuniverse"),
- "Set the universe for a directory."),
- Definition(
- MBold("setup"),
- "Initialize a directory to be managed."),
- Definition(
- MBold("share") & " " & Argument("filename"),
- "Share a package advertisement on a bazaar."),
- Definition(
- MBold("share") & " " & CmdOption("i", Argument("descriptor")),
- "The package advertisement is usually specified in a file, " &
- "but it may also be specified on the command line with the " &
- CmdOption("i") & " option."),
- Definition(
- MBold("share") & " " & CmdOptionLong("template"),
- "If " & CmdOptionLong("template") & " is specified, then instead " &
- "of uploading a description, the command prints out a template " &
- "of a package advertisement."),
- Definition(
- MBold("show"),
- "Show information about one package."),
- Definition(
- MBold("update"),
- "Update the list of available packages."),
- Definition(
- MBold("upgrade"),
- "Upgrade all possible packages."))))
-
- val examples = Section("EXAMPLES",
-
- DefinitionList(
- Definition(
- "Update the list of available packages.",
- CmdLine(MBold("update"))),
- Definition(
- "Upload package description for " & Mono("scala-devel-2.5.1") &
- " to the universe",
- CmdLine(MBold("share") & " scala-devel-2.5.1.advert"))))
-
- val exitStatus = Section("EXIT STATUS",
-
- MBold(command) & " returns a zero exist status if it succeeds to process " &
- "the specified input files. Non zero is returned in case of failure.")
-
- override val authors = Section("AUTHOR",
-
- "Written by Lex Spoon.")
-
- val seeAlso = Section("SEE ALSO",
-
- Link(Bold("fsc") & "(1)", "fsc.html") & ", " &
- Link(Bold("scala") & "(1)", "scala.html") & ", " &
- Link(Bold("scalac") & "(1)", "scalac.html") & ", " &
- Link(Bold("scaladoc") & "(1)", "scaladoc.html") & ", " &
- Link(Bold("scalap") & "(1)", "scalap.html"))
-
- def manpage = new Document {
- title = command
- date = "August 2006"
- author = "Stephane Micheloud"
- version = "0.3"
- sections = List(
- name,
- synopsis,
- parameters,
- description,
- options,
- examples,
- exitStatus,
- authors,
- bugs,
- copyright,
- seeAlso)
- }
-}
diff --git a/src/manual/scala/man1/scala.scala b/src/manual/scala/man1/scala.scala
index 368453f3a9..8daab84d3e 100644
--- a/src/manual/scala/man1/scala.scala
+++ b/src/manual/scala/man1/scala.scala
@@ -250,7 +250,6 @@ object scala extends Command {
val seeAlso = Section("SEE ALSO",
Link(Bold("fsc") & "(1)", "fsc.html") & ", " &
- Link(Bold("sbaz") & "(1)", "sbaz.html") & ", " &
Link(Bold("scalac") & "(1)", "scalac.html") & ", " &
Link(Bold("scaladoc") & "(1)", "scaladoc.html") & ", " &
Link(Bold("scalap") & "(1)", "scalap.html"))
diff --git a/src/manual/scala/man1/scalac.scala b/src/manual/scala/man1/scalac.scala
index b84510ee16..49324ffa83 100644
--- a/src/manual/scala/man1/scalac.scala
+++ b/src/manual/scala/man1/scalac.scala
@@ -174,6 +174,8 @@ object scalac extends Command {
Definition(
Mono(Bold("@") & Argument("file")),
"A text file containing compiler arguments (options and source files)")
+
+ // TODO - Add macros an dsuch here.
)
),
@@ -424,14 +426,13 @@ object scalac extends Command {
val seeAlso = Section("SEE ALSO",
Link(Bold("fsc") & "(1)", "fsc.html") & ", " &
- Link(Bold("sbaz") & "(1)", "sbaz.html") & ", " &
Link(Bold("scala") & "(1)", "scala.html") & ", " &
Link(Bold("scaladoc") & "(1)", "scaladoc.html") & ", " &
Link(Bold("scalap") & "(1)", "scalap.html"))
def manpage = new Document {
title = command
- date = "September 2011"
+ date = "March 2012"
author = "Stephane Micheloud"
version = "1.0"
sections = List(
diff --git a/src/manual/scala/man1/scaladoc.scala b/src/manual/scala/man1/scaladoc.scala
index a6832be4b0..193c77fc51 100644
--- a/src/manual/scala/man1/scaladoc.scala
+++ b/src/manual/scala/man1/scaladoc.scala
@@ -137,7 +137,6 @@ object scaladoc extends Command {
val seeAlso = Section("SEE ALSO",
Link(Bold("fsc") & "(1)", "fsc.html") & ", " &
- Link(Bold("sbaz") & "(1)", "sbaz.html") & ", " &
Link(Bold("scala") & "(1)", "scala.html") & ", " &
Link(Bold("scalac") & "(1)", "scalac.html") & ", " &
Link(Bold("scalap") & "(1)", "scalap.html"))
diff --git a/src/manual/scala/man1/scalap.scala b/src/manual/scala/man1/scalap.scala
index cc9b312dac..88fc91957f 100644
--- a/src/manual/scala/man1/scalap.scala
+++ b/src/manual/scala/man1/scalap.scala
@@ -86,7 +86,6 @@ object scalap extends Command {
val seeAlso = Section("SEE ALSO",
Link(Bold("fsc") & "(1)", "fsc.html") & ", " &
- Link(Bold("sbaz") & "(1)", "sbaz.html") & ", " &
Link(Bold("scala") & "(1)", "scala.html") & ", " &
Link(Bold("scalac") & "(1)", "scalac.html") & ", " &
Link(Bold("scaladoc") & "(1)", "scaladoc.html"))
diff --git a/src/manual/scala/tools/docutil/resources/index.html b/src/manual/scala/tools/docutil/resources/index.html
index 4e5130aa3d..d1f3bd81f4 100644
--- a/src/manual/scala/tools/docutil/resources/index.html
+++ b/src/manual/scala/tools/docutil/resources/index.html
@@ -44,8 +44,8 @@
<ul class="ContentList">
<li>
- <a href="#basic"><b class="SansSerif">Basic Tools</b></a> (<code>sbaz</code>,
- <code>fsc</code>, <code>scala</code>, <code>scalac</code>, <code>scaladoc</code>,
+ <a href="#basic"><b class="SansSerif">Basic Tools</b></a> (<code>fsc</code>,
+ <code>scala</code>, <code>scalac</code>, <code>scaladoc</code>,
<code>scalap</code>)
</li>
</ul>
@@ -133,17 +133,6 @@
</tr>
<tr>
<td width="13%" valign="top">
- <span class="tool">sbaz</span>
- </td>
- <td width="70%" valign="top">
- The Scala sharing tool.
- </td>
- <td width="17%" valign="top" class="links">
- [<a href="sbaz.html">Solaris, Linux and Windows</a>]
- </td>
- </tr>
- <tr>
- <td width="13%" valign="top">
<span class="tool">scala</span>
</td>
<td width="70%" valign="top">
@@ -191,7 +180,7 @@
<hr/>
<div style="font-size:x-small;">
- Copyright (c) 2002-2011 <a href="http://www.epfl.ch/">EPFL</a>,
+ Copyright (c) 2002-2012 <a href="http://www.epfl.ch/">EPFL</a>,
Lausanne, unless specified otherwise.<br/>
All rights reserved.
</div>
diff --git a/src/partest/scala/tools/partest/PartestTask.scala b/src/partest/scala/tools/partest/PartestTask.scala
index 524dc06327..ad2e155182 100644
--- a/src/partest/scala/tools/partest/PartestTask.scala
+++ b/src/partest/scala/tools/partest/PartestTask.scala
@@ -299,6 +299,16 @@ class PartestTask extends Task with CompilationPathProperty {
}
} getOrElse sys.error("Provided classpath does not contain a Scala partest.")
+ val scalaActors = {
+ (classpath.list map { fs => new File(fs) }) find { f =>
+ f.getName match {
+ case "scala-actors.jar" => true
+ case "actors" if (f.getParentFile.getName == "classes") => true
+ case _ => false
+ }
+ }
+ } getOrElse sys.error("Provided classpath does not contain a Scala actors.")
+
def scalacArgsFlat: Option[Seq[String]] = scalacArgs map (_ flatMap { a =>
val parts = a.getParts
if(parts eq null) Seq[String]() else parts.toSeq
@@ -324,6 +334,7 @@ class PartestTask extends Task with CompilationPathProperty {
antFileManager.LATEST_LIB = scalaLibrary.getAbsolutePath
antFileManager.LATEST_COMP = scalaCompiler.getAbsolutePath
antFileManager.LATEST_PARTEST = scalaPartest.getAbsolutePath
+ antFileManager.LATEST_ACTORS = scalaActors.getAbsolutePath
javacmd foreach (x => antFileManager.JAVACMD = x.getAbsolutePath)
javaccmd foreach (x => antFileManager.JAVAC_CMD = x.getAbsolutePath)
diff --git a/src/partest/scala/tools/partest/ScaladocModelTest.scala b/src/partest/scala/tools/partest/ScaladocModelTest.scala
new file mode 100644
index 0000000000..2eb026ceee
--- /dev/null
+++ b/src/partest/scala/tools/partest/ScaladocModelTest.scala
@@ -0,0 +1,124 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Vlad Ureche
+ */
+
+package scala.tools.partest
+
+import scala.tools.partest._
+import java.io._
+import scala.tools.nsc._
+import scala.tools.nsc.util.CommandLineParser
+import scala.tools.nsc.doc.{Settings, DocFactory, Universe}
+import scala.tools.nsc.doc.model._
+import scala.tools.nsc.reporters.ConsoleReporter
+
+/** A class for testing scaladoc model generation
+ * - you need to specify the code in the `code` method
+ * - you need to override the testModel method to test the model
+ * - you may specify extra parameters to send to scaladoc in `scaladocSettings`
+ * {{{
+ import scala.tools.nsc.doc.model._
+ import scala.tools.partest.ScaladocModelTest
+
+ object Test extends ScaladocModelTest {
+
+ def code = """ ... """
+ def scaladocSettings = ""
+ def testModel(rootPackage: Package) = {
+ // get the quick access implicit defs in scope (_package(s), _class(es), _trait(s), object(s) _method(s), _value(s))
+ import access._
+
+ // just need to check the member exists, access methods will throw an error if there's a problem
+ rootPackage._package("scala")._package("test")._class("C")._method("foo")
+ }
+ }
+ * }}}
+ */
+abstract class ScaladocModelTest extends DirectTest {
+
+ /** Override this to give scaladoc command line parameters */
+ def scaladocSettings: String
+
+ /** Override this to test the model */
+ def testModel(root: Package): Unit
+
+ // Implementation follows:
+ override def extraSettings: String = "-usejavacp"
+
+ override def show(): Unit = {
+ // redirect err to out, for logging
+ val prevErr = System.err
+ System.setErr(System.out)
+
+ try {
+ // 1 - compile with scaladoc and get the model out
+ val args = scaladocSettings.split(" ")
+ val universe = model(args:_*).getOrElse({sys.error("Scaladoc Model Test ERROR: No universe generated!")})
+ // 2 - check the model generated
+ testModel(universe.rootPackage)
+ } catch {
+ case e =>
+ println(e)
+ e.printStackTrace
+ }
+ // set err back to the real err handler
+ System.setErr(prevErr)
+ }
+
+ // create a new scaladoc compiler
+ def newDocFactory(args: String*): DocFactory = {
+ val settings = new Settings(_ => ())
+ val command = new ScalaDoc.Command((CommandLineParser tokenize extraSettings) ++ args.toList, settings)
+ val docFact = new DocFactory(new ConsoleReporter(settings), settings)
+ docFact
+ }
+
+ // compile with scaladoc and output the result
+ def model(args: String*): Option[Universe] = newDocFactory(args: _*).makeUniverse(Right(code))
+
+ // so we don't get the newSettings warning
+ override def isDebug = false
+
+
+ // finally, enable easy navigation inside the entities
+ object access {
+
+ // Make it easy to access things
+ class TemplateAccess(tpl: DocTemplateEntity) {
+
+ def _class(name: String): DocTemplateEntity = getTheFirst(_classes(name), tpl.qualifiedName + ".class(" + name + ")")
+ def _classes(name: String): List[DocTemplateEntity] = tpl.templates.filter(_.name == name).flatMap({ case c: Class => List(c)})
+
+ def _trait(name: String): DocTemplateEntity = getTheFirst(_traits(name), tpl.qualifiedName + ".trait(" + name + ")")
+ def _traits(name: String): List[DocTemplateEntity] = tpl.templates.filter(_.name == name).flatMap({ case t: Trait => List(t)})
+
+ def _object(name: String): DocTemplateEntity = getTheFirst(_objects(name), tpl.qualifiedName + ".object(" + name + ")")
+ def _objects(name: String): List[DocTemplateEntity] = tpl.templates.filter(_.name == name).flatMap({ case o: Object => List(o)})
+
+ def _method(name: String): Def = getTheFirst(_methods(name), tpl.qualifiedName + ".method(" + name + ")")
+ def _methods(name: String): List[Def] = tpl.methods.filter(_.name == name)
+
+ def _value(name: String): Val = getTheFirst(_values(name), tpl.qualifiedName + ".value(" + name + ")")
+ def _values(name: String): List[Val] = tpl.values.filter(_.name == name)
+
+ def getTheFirst[T](list: List[T], expl: String): T = {
+ if (list.length == 1)
+ list.head
+ else if (list.length == 0)
+ sys.error("Error getting " + expl + ": No such element. All elements in list: [" + list.mkString(", ") + "]")
+ else
+ sys.error("Error getting " + expl + ": " + list.length + " elements with this name. " +
+ "All elements in list: [" + list.mkString(", ") + "]")
+ }
+ }
+
+ class PackageAccess(pack: Package) extends TemplateAccess(pack) {
+ def _package(name: String): Package = getTheFirst(_packages(name), pack.qualifiedName + ".package(" + name + ")")
+ def _packages(name: String): List[Package] = pack.packages.filter(_.name == name)
+ }
+
+ implicit def templateAccess(tpl: DocTemplateEntity) = new TemplateAccess(tpl)
+ implicit def packageAccess(pack: Package) = new PackageAccess(pack)
+ }
+}
diff --git a/src/partest/scala/tools/partest/nest/AntRunner.scala b/src/partest/scala/tools/partest/nest/AntRunner.scala
index 4795e5551a..e77385d6e9 100644
--- a/src/partest/scala/tools/partest/nest/AntRunner.scala
+++ b/src/partest/scala/tools/partest/nest/AntRunner.scala
@@ -22,6 +22,7 @@ class AntRunner extends DirectRunner {
var LATEST_LIB: String = _
var LATEST_COMP: String = _
var LATEST_PARTEST: String = _
+ var LATEST_ACTORS: String = _
val testRootPath: String = "test"
val testRootDir: Directory = Directory(testRootPath)
}
diff --git a/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala b/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala
index 3d72227b04..fa533eeb10 100644
--- a/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala
+++ b/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala
@@ -83,6 +83,7 @@ class ConsoleFileManager extends FileManager {
latestFile = testClassesDir.parent / "bin"
latestLibFile = testClassesDir / "library"
+ latestActorsFile = testClassesDir / "library" / "actors"
latestCompFile = testClassesDir / "compiler"
latestPartestFile = testClassesDir / "partest"
latestFjbgFile = testParent / "lib" / "fjbg.jar"
@@ -92,6 +93,7 @@ class ConsoleFileManager extends FileManager {
NestUI.verbose("Running on "+dir)
latestFile = dir / "bin"
latestLibFile = dir / "lib/scala-library.jar"
+ latestActorsFile = dir / "lib/scala-actors.jar"
latestCompFile = dir / "lib/scala-compiler.jar"
latestPartestFile = dir / "lib/scala-partest.jar"
}
@@ -100,6 +102,7 @@ class ConsoleFileManager extends FileManager {
NestUI.verbose("Running build/quick")
latestFile = prefixFile("build/quick/bin")
latestLibFile = prefixFile("build/quick/classes/library")
+ latestActorsFile = prefixFile("build/quick/classes/library/actors")
latestCompFile = prefixFile("build/quick/classes/compiler")
latestPartestFile = prefixFile("build/quick/classes/partest")
}
@@ -109,6 +112,7 @@ class ConsoleFileManager extends FileManager {
val p = testParent.getParentFile
latestFile = prefixFileWith(p, "bin")
latestLibFile = prefixFileWith(p, "lib/scala-library.jar")
+ latestActorsFile = prefixFileWith(p, "lib/scala-actors.jar")
latestCompFile = prefixFileWith(p, "lib/scala-compiler.jar")
latestPartestFile = prefixFileWith(p, "lib/scala-partest.jar")
}
@@ -117,6 +121,7 @@ class ConsoleFileManager extends FileManager {
NestUI.verbose("Running dists/latest")
latestFile = prefixFile("dists/latest/bin")
latestLibFile = prefixFile("dists/latest/lib/scala-library.jar")
+ latestActorsFile = prefixFile("dists/latest/lib/scala-actors.jar")
latestCompFile = prefixFile("dists/latest/lib/scala-compiler.jar")
latestPartestFile = prefixFile("dists/latest/lib/scala-partest.jar")
}
@@ -125,6 +130,7 @@ class ConsoleFileManager extends FileManager {
NestUI.verbose("Running build/pack")
latestFile = prefixFile("build/pack/bin")
latestLibFile = prefixFile("build/pack/lib/scala-library.jar")
+ latestActorsFile = prefixFile("build/pack/lib/scala-actors.jar")
latestCompFile = prefixFile("build/pack/lib/scala-compiler.jar")
latestPartestFile = prefixFile("build/pack/lib/scala-partest.jar")
}
@@ -159,14 +165,17 @@ class ConsoleFileManager extends FileManager {
LATEST_LIB = latestLibFile.getAbsolutePath
LATEST_COMP = latestCompFile.getAbsolutePath
LATEST_PARTEST = latestPartestFile.getAbsolutePath
+ LATEST_ACTORS = latestActorsFile.getAbsolutePath
}
var LATEST_LIB: String = ""
var LATEST_COMP: String = ""
var LATEST_PARTEST: String = ""
+ var LATEST_ACTORS: String = ""
var latestFile: File = _
var latestLibFile: File = _
+ var latestActorsFile: File = _
var latestCompFile: File = _
var latestPartestFile: File = _
var latestFjbgFile: File = _
diff --git a/src/partest/scala/tools/partest/nest/DirectRunner.scala b/src/partest/scala/tools/partest/nest/DirectRunner.scala
index d3d50ca58c..20f435cfbb 100644
--- a/src/partest/scala/tools/partest/nest/DirectRunner.scala
+++ b/src/partest/scala/tools/partest/nest/DirectRunner.scala
@@ -57,13 +57,14 @@ trait DirectRunner {
// for example, see how it's done in ReflectiveRunner
//val consFM = new ConsoleFileManager
//import consFM.{ latestCompFile, latestLibFile, latestPartestFile }
- val latestCompFile = new File(fileManager.LATEST_COMP);
- val latestLibFile = new File(fileManager.LATEST_LIB);
- val latestPartestFile = new File(fileManager.LATEST_PARTEST);
+ val latestCompFile = new File(fileManager.LATEST_COMP)
+ val latestLibFile = new File(fileManager.LATEST_LIB)
+ val latestPartestFile = new File(fileManager.LATEST_PARTEST)
+ val latestActorsFile = new File(fileManager.LATEST_ACTORS)
val scalacheckURL = PathSettings.scalaCheck.toURL
val scalaCheckParentClassLoader = ScalaClassLoader.fromURLs(
- List(scalacheckURL, latestCompFile.toURI.toURL, latestLibFile.toURI.toURL, latestPartestFile.toURI.toURL)
+ scalacheckURL :: (List(latestCompFile, latestLibFile, latestActorsFile, latestPartestFile).map(_.toURI.toURL))
)
Output.init()
diff --git a/src/partest/scala/tools/partest/nest/FileManager.scala b/src/partest/scala/tools/partest/nest/FileManager.scala
index a4a94fe93e..6d9e64730f 100644
--- a/src/partest/scala/tools/partest/nest/FileManager.scala
+++ b/src/partest/scala/tools/partest/nest/FileManager.scala
@@ -62,6 +62,7 @@ trait FileManager extends FileUtil {
var LATEST_LIB: String
var LATEST_COMP: String
var LATEST_PARTEST: String
+ var LATEST_ACTORS: String
var showDiff = false
var updateCheck = false
diff --git a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala
index 5cde63dc81..a0511774a9 100644
--- a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala
+++ b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala
@@ -48,9 +48,9 @@ class ReflectiveRunner {
new ConsoleFileManager
import fileManager.
- { latestCompFile, latestLibFile, latestPartestFile, latestFjbgFile, latestScalapFile }
+ { latestCompFile, latestLibFile, latestPartestFile, latestFjbgFile, latestScalapFile, latestActorsFile }
val files =
- Array(latestCompFile, latestLibFile, latestPartestFile, latestFjbgFile, latestScalapFile) map (x => io.File(x))
+ Array(latestCompFile, latestLibFile, latestPartestFile, latestFjbgFile, latestScalapFile, latestActorsFile) map (x => io.File(x))
val sepUrls = files map (_.toURL)
var sepLoader = new URLClassLoader(sepUrls, null)
diff --git a/src/partest/scala/tools/partest/nest/SBTRunner.scala b/src/partest/scala/tools/partest/nest/SBTRunner.scala
index 4c6f417df5..750e270c18 100644
--- a/src/partest/scala/tools/partest/nest/SBTRunner.scala
+++ b/src/partest/scala/tools/partest/nest/SBTRunner.scala
@@ -15,6 +15,7 @@ object SBTRunner extends DirectRunner {
var LATEST_LIB: String = _
var LATEST_COMP: String = _
var LATEST_PARTEST: String = _
+ var LATEST_ACTORS: String = _
val testRootPath: String = "test"
val testRootDir: Directory = Directory(testRootPath)
}
@@ -60,6 +61,9 @@ object SBTRunner extends DirectRunner {
fileManager.LATEST_COMP = comp getOrElse sys.error("No scala-compiler found! Classpath = " + fileManager.CLASSPATH)
val partest: Option[String] = (fileManager.CLASSPATH split File.pathSeparator filter (_ matches ".*scala-partest.*\\.jar")).headOption
fileManager.LATEST_PARTEST = partest getOrElse sys.error("No scala-partest found! Classpath = " + fileManager.CLASSPATH)
+ val actors: Option[String] = (fileManager.CLASSPATH split File.pathSeparator filter (_ matches ".*scala-actors.*\\.jar")).headOption
+ fileManager.LATEST_ACTORS = actors getOrElse sys.error("No scala-actors found! Classpath = " + fileManager.CLASSPATH)
+
// TODO - Do something useful here!!!
fileManager.JAVAC_CMD = "javac"
fileManager.failed = config.justFailedTests
diff --git a/src/partest/scala/tools/partest/nest/Worker.scala b/src/partest/scala/tools/partest/nest/Worker.scala
index 3f2cb16082..cb6f2a0edc 100644
--- a/src/partest/scala/tools/partest/nest/Worker.scala
+++ b/src/partest/scala/tools/partest/nest/Worker.scala
@@ -55,6 +55,7 @@ class ScalaCheckFileManager(val origmanager: FileManager) extends FileManager {
var LATEST_LIB: String = origmanager.LATEST_LIB
var LATEST_COMP: String = origmanager.LATEST_COMP
var LATEST_PARTEST: String = origmanager.LATEST_PARTEST
+ var LATEST_ACTORS: String = origmanager.LATEST_ACTORS
}
object Output {