summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/actors/scala/actors/AbstractActor.scala2
-rw-r--r--src/actors/scala/actors/Actor.scala112
-rw-r--r--src/actors/scala/actors/ActorCanReply.scala101
-rw-r--r--src/actors/scala/actors/ActorTask.scala27
-rw-r--r--src/actors/scala/actors/CanReply.scala8
-rw-r--r--src/actors/scala/actors/Channel.scala39
-rw-r--r--src/actors/scala/actors/Reactor.scala4
-rw-r--r--src/actors/scala/actors/ReactorCanReply.scala6
-rw-r--r--src/actors/scala/actors/ReactorTask.scala34
-rw-r--r--src/actors/scala/actors/UncaughtException.scala11
-rw-r--r--src/actors/scala/actors/remote/Proxy.scala6
-rw-r--r--src/actors/scala/actors/remote/RemoteActor.scala27
-rw-r--r--src/build/pack.xml3
-rw-r--r--src/compiler/scala/tools/cmd/CommandLine.scala50
-rw-r--r--src/compiler/scala/tools/cmd/Demo.scala7
-rw-r--r--src/compiler/scala/tools/cmd/Instance.scala3
-rw-r--r--src/compiler/scala/tools/cmd/Interpolation.scala6
-rw-r--r--src/compiler/scala/tools/cmd/Meta.scala21
-rw-r--r--src/compiler/scala/tools/cmd/Opt.scala8
-rw-r--r--src/compiler/scala/tools/cmd/Reference.scala3
-rw-r--r--src/compiler/scala/tools/cmd/Spec.scala11
-rw-r--r--src/compiler/scala/tools/cmd/program/Scmp.scala59
-rw-r--r--src/compiler/scala/tools/cmd/program/Simple.scala81
-rw-r--r--src/compiler/scala/tools/cmd/program/Tokens.scala100
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala37
-rw-r--r--src/compiler/scala/tools/nsc/Interpreter.scala221
-rw-r--r--src/compiler/scala/tools/nsc/InterpreterLoop.scala61
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeInfo.scala44
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala5
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala3
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala38
-rw-r--r--src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala46
-rw-r--r--src/compiler/scala/tools/nsc/doc/DocFactory.scala2
-rw-r--r--src/compiler/scala/tools/nsc/doc/Settings.scala2
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala6
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/page/Index.scala45
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/page/Template.scala7
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/resource/lib/index.css11
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/resource/lib/template.css9
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala8
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ByteCode.scala7
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Completion.scala334
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/CompletionAware.scala33
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala88
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/IdentCompletion.scala25
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/LiteralCompletion.scala50
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/PackageCompletion.scala187
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Parsed.scala14
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ProductCompletion.scala2
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ReflectionCompletion.scala18
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/XMLCompletion.scala1
-rw-r--r--src/compiler/scala/tools/nsc/io/Process.scala22
-rw-r--r--src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala2
-rw-r--r--src/compiler/scala/tools/nsc/settings/MutableSettings.scala8
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala18
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala8
-rw-r--r--src/compiler/scala/tools/nsc/symtab/StdNames.scala21
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala15
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala13
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala1
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala107
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala223
-rw-r--r--src/compiler/scala/tools/nsc/transform/TailCalls.scala144
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Analyzer.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala41
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Duplicators.scala16
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala49
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala137
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala58
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala53
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala21
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala268
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala305
-rwxr-xr-xsrc/compiler/scala/tools/nsc/util/Chars.scala11
-rw-r--r--src/compiler/scala/tools/nsc/util/ShowPickled.scala17
-rw-r--r--src/compiler/scala/tools/nsc/util/SourceFile.scala2
-rw-r--r--src/library/scala/Array.scala5
-rw-r--r--src/library/scala/collection/BitSet.scala2
-rw-r--r--src/library/scala/collection/BitSetLike.scala2
-rw-r--r--src/library/scala/collection/Iterator.scala11
-rw-r--r--src/library/scala/collection/SeqLike.scala24
-rw-r--r--src/library/scala/collection/Set.scala1
-rw-r--r--src/library/scala/collection/generic/BitSetFactory.scala4
-rw-r--r--src/library/scala/collection/generic/ImmutableSetFactory.scala (renamed from src/library/scala/concurrent/AsyncInvokable.scala)18
-rw-r--r--src/library/scala/collection/generic/MutableSetFactory.scala18
-rw-r--r--src/library/scala/collection/generic/SetFactory.scala4
-rw-r--r--src/library/scala/collection/generic/TraversableFactory.scala8
-rw-r--r--src/library/scala/collection/immutable/BitSet.scala5
-rwxr-xr-xsrc/library/scala/collection/immutable/DefaultMap.scala2
-rw-r--r--src/library/scala/collection/immutable/HashSet.scala2
-rw-r--r--src/library/scala/collection/immutable/List.scala6
-rw-r--r--src/library/scala/collection/immutable/ListSet.scala2
-rw-r--r--src/library/scala/collection/immutable/Queue.scala26
-rw-r--r--src/library/scala/collection/immutable/Range.scala17
-rw-r--r--src/library/scala/collection/immutable/Set.scala2
-rw-r--r--src/library/scala/collection/immutable/Stack.scala3
-rw-r--r--src/library/scala/collection/immutable/Stream.scala10
-rw-r--r--src/library/scala/collection/immutable/TreeSet.scala2
-rw-r--r--src/library/scala/collection/mutable/AddingBuilder.scala9
-rw-r--r--src/library/scala/collection/mutable/BitSet.scala4
-rw-r--r--src/library/scala/collection/mutable/GrowingBuilder.scala5
-rw-r--r--src/library/scala/collection/mutable/HashSet.scala2
-rw-r--r--src/library/scala/collection/mutable/IndexedSeqLike.scala2
-rw-r--r--src/library/scala/collection/mutable/LinkedHashSet.scala2
-rw-r--r--src/library/scala/collection/mutable/MapLike.scala5
-rw-r--r--src/library/scala/collection/mutable/Set.scala2
-rw-r--r--src/library/scala/collection/mutable/StringBuilder.scala814
-rw-r--r--src/library/scala/concurrent/TaskRunner.scala5
-rw-r--r--src/library/scala/concurrent/ThreadRunner.scala10
-rw-r--r--src/library/scala/concurrent/ops.scala16
-rw-r--r--src/library/scala/math/BigDecimal.scala21
-rw-r--r--src/library/scala/reflect/Manifest.scala15
-rwxr-xr-xsrc/library/scala/reflect/generic/Flags.scala7
-rwxr-xr-xsrc/library/scala/reflect/generic/Trees.scala1
-rw-r--r--src/library/scala/runtime/RichChar.scala1
-rw-r--r--src/library/scala/transient.scala3
-rw-r--r--src/library/scala/util/parsing/combinator/RegexParsers.scala19
-rw-r--r--src/library/scala/volatile.scala3
-rw-r--r--src/library/scala/xml/NodeSeq.scala45
-rw-r--r--src/library/scala/xml/Utility.scala25
-rw-r--r--src/library/scala/xml/Xhtml.scala10
-rw-r--r--src/partest/scala/tools/partest/Actions.scala119
-rw-r--r--src/partest/scala/tools/partest/Categories.scala2
-rw-r--r--src/partest/scala/tools/partest/Compilable.scala14
-rw-r--r--src/partest/scala/tools/partest/Config.scala2
-rw-r--r--src/partest/scala/tools/partest/Entities.scala5
-rw-r--r--src/partest/scala/tools/partest/Partest.scala4
-rw-r--r--src/partest/scala/tools/partest/PartestSpec.scala3
-rw-r--r--src/partest/scala/tools/partest/Results.scala2
-rw-r--r--src/partest/scala/tools/partest/category/AllCategories.scala2
-rw-r--r--src/partest/scala/tools/partest/category/Analysis.scala2
-rw-r--r--src/partest/scala/tools/partest/category/Compiler.scala6
-rw-r--r--src/partest/scala/tools/partest/io/Logging.scala10
-rw-r--r--src/scalap/scala/tools/scalap/Decode.scala27
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala4
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/scalasig/Type.scala1
-rw-r--r--src/swing/scala/swing/EditorPane.scala2
-rw-r--r--src/swing/scala/swing/FlowPanel.scala4
-rw-r--r--src/swing/scala/swing/FormattedTextField.scala2
-rw-r--r--src/swing/scala/swing/GridBagPanel.scala6
-rw-r--r--src/swing/scala/swing/GridPanel.scala3
-rw-r--r--src/swing/scala/swing/Label.scala3
-rw-r--r--src/swing/scala/swing/ListView.scala2
-rw-r--r--src/swing/scala/swing/MainFrame.scala2
-rw-r--r--src/swing/scala/swing/Menu.scala2
-rw-r--r--src/swing/scala/swing/PasswordField.scala2
-rw-r--r--src/swing/scala/swing/ProgressBar.scala2
-rw-r--r--src/swing/scala/swing/RadioButton.scala2
-rw-r--r--src/swing/scala/swing/ScrollBar.scala2
-rw-r--r--src/swing/scala/swing/ScrollPane.scala2
-rw-r--r--src/swing/scala/swing/Separator.scala2
-rw-r--r--src/swing/scala/swing/Slider.scala2
-rw-r--r--src/swing/scala/swing/SplitPane.scala2
-rw-r--r--src/swing/scala/swing/TabbedPane.scala2
-rw-r--r--src/swing/scala/swing/Table.scala2
-rw-r--r--src/swing/scala/swing/TextArea.scala5
-rw-r--r--src/swing/scala/swing/ToggleButton.scala2
162 files changed, 2752 insertions, 2317 deletions
diff --git a/src/actors/scala/actors/AbstractActor.scala b/src/actors/scala/actors/AbstractActor.scala
index 80b1e76b30..f97a1c3e2a 100644
--- a/src/actors/scala/actors/AbstractActor.scala
+++ b/src/actors/scala/actors/AbstractActor.scala
@@ -19,6 +19,8 @@ package scala.actors
*/
trait AbstractActor extends OutputChannel[Any] with CanReply[Any, Any] {
+ type Future[+R] = scala.actors.Future[R]
+
private[actors] def exiting: Boolean = false
private[actors] def linkTo(to: AbstractActor): Unit
diff --git a/src/actors/scala/actors/Actor.scala b/src/actors/scala/actors/Actor.scala
index ccd60f666c..4e245f27cf 100644
--- a/src/actors/scala/actors/Actor.scala
+++ b/src/actors/scala/actors/Actor.scala
@@ -12,7 +12,6 @@ package scala.actors
import scala.util.control.ControlThrowable
import java.util.{Timer, TimerTask}
-import java.util.concurrent.{ExecutionException, Callable}
/**
* The <code>Actor</code> object provides functions for the definition of
@@ -117,17 +116,17 @@ object Actor extends Combinators {
}
/**
- * <p>This is a factory method for creating actors.</p>
+ * This is a factory method for creating actors.
*
- * <p>The following example demonstrates its usage:</p>
+ * The following example demonstrates its usage:
*
- * <pre>
+ * {{{
* import scala.actors.Actor._
* ...
* val a = actor {
* ...
* }
- * </pre>
+ * }}}
*
* @param body the code block to be executed by the newly created actor
* @return the newly created actor. Note that it is automatically started.
@@ -142,14 +141,12 @@ object Actor extends Combinators {
}
/**
- * <p>
* This is a factory method for creating actors whose
- * body is defined using a <code>Responder</code>.
- * </p>
+ * body is defined using a `Responder`.
*
- * <p>The following example demonstrates its usage:</p>
+ * The following example demonstrates its usage:
*
- * <pre>
+ * {{{
* import scala.actors.Actor._
* import Responder.exec
* ...
@@ -159,9 +156,9 @@ object Actor extends Combinators {
* if exec(println("result: "+res))
* } yield {}
* }
- * </pre>
+ * }}}
*
- * @param body the <code>Responder</code> to be executed by the newly created actor
+ * @param body the `Responder` to be executed by the newly created actor
* @return the newly created actor. Note that it is automatically started.
*/
def reactor(body: => Responder[Unit]): Actor = {
@@ -275,20 +272,18 @@ object Actor extends Combinators {
def mailboxSize: Int = rawSelf.mailboxSize
/**
- * <p>
* Converts a synchronous event-based operation into
- * an asynchronous <code>Responder</code>.
- * </p>
+ * an asynchronous `Responder`.
*
- * <p>The following example demonstrates its usage:</p>
+ * The following example demonstrates its usage:
*
- * <pre>
+ * {{{
* val adder = reactor {
* for {
* _ <- respondOn(react) { case Add(a, b) => reply(a+b) }
* } yield {}
* }
- * </pre>
+ * }}}
*/
def respondOn[A, B](fun: PartialFunction[A, Unit] => Nothing):
PartialFunction[A, B] => Responder[B] =
@@ -325,7 +320,7 @@ object Actor extends Combinators {
*
* @param from the actor to unlink from
*/
- def unlink(from: Actor): Unit = self.unlink(from)
+ def unlink(from: AbstractActor): Unit = self.unlink(from)
/**
* <p>
@@ -413,6 +408,43 @@ trait Actor extends AbstractActor with ReplyReactor with ActorCanReply with Inpu
}
} 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)
@@ -695,37 +727,51 @@ trait Actor extends AbstractActor with ReplyReactor with ActorCanReply with Inpu
* <code>reason != 'normal</code>.
* </p>
*/
- protected[actors] def exit(reason: AnyRef): Nothing = synchronized {
- exitReason = reason
+ protected[actors] def exit(reason: AnyRef): Nothing = {
+ synchronized {
+ exitReason = reason
+ }
exit()
}
/**
* Terminates with exit reason <code>'normal</code>.
*/
- protected[actors] override def exit(): Nothing = synchronized {
- if (!links.isEmpty)
- exitLinked()
+ 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() {
+ 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.==)
- // exit linked processes
- mylinks.foreach((linked: AbstractActor) => {
- unlink(linked)
- if (!linked.exiting)
- linked.exit(this, exitReason)
- })
+ // unlink actors
+ mylinks.foreach(unlinkFrom(_))
+ // return closure that locks linked actors
+ () => {
+ mylinks.foreach((linked: AbstractActor) => {
+ linked.synchronized {
+ if (!linked.exiting)
+ linked.exit(this, exitReason)
+ }
+ })
+ }
}
// Assume !links.isEmpty
// guarded by this
- private[actors] def exitLinked(reason: AnyRef) {
+ private[actors] def exitLinked(reason: AnyRef): () => Unit = {
exitReason = reason
exitLinked()
}
@@ -745,6 +791,8 @@ trait Actor extends AbstractActor with ReplyReactor with ActorCanReply with Inpu
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
diff --git a/src/actors/scala/actors/ActorCanReply.scala b/src/actors/scala/actors/ActorCanReply.scala
index fdc3833ec4..a6a81815c1 100644
--- a/src/actors/scala/actors/ActorCanReply.scala
+++ b/src/actors/scala/actors/ActorCanReply.scala
@@ -10,8 +10,6 @@
package scala.actors
-import java.util.concurrent.ExecutionException
-
/**
* The `ActorCanReply` trait provides message send operations that
* may result in a response from the receiver.
@@ -19,19 +17,17 @@ import java.util.concurrent.ExecutionException
* @author Philipp Haller
*/
private[actors] trait ActorCanReply extends ReactorCanReply {
- thiz: AbstractActor with ReplyReactor =>
+ this: AbstractActor with ReplyReactor =>
override def !?(msg: Any): Any = {
- val replyCh = new Channel[Any](Actor.self(thiz.scheduler))
- thiz.send(msg, replyCh)
- replyCh.receive {
- case x => x
- }
+ val replyCh = new Channel[Any](Actor.self(scheduler))
+ send(msg, replyCh)
+ replyCh.?
}
override def !?(msec: Long, msg: Any): Option[Any] = {
- val replyCh = new Channel[Any](Actor.self(thiz.scheduler))
- thiz.send(msg, replyCh)
+ val replyCh = new Channel[Any](Actor.self(scheduler))
+ send(msg, replyCh)
replyCh.receiveWithin(msec) {
case TIMEOUT => None
case x => Some(x)
@@ -39,8 +35,8 @@ private[actors] trait ActorCanReply extends ReactorCanReply {
}
override def !![A](msg: Any, handler: PartialFunction[Any, A]): Future[A] = {
- val ftch = new Channel[A](Actor.self(thiz.scheduler))
- thiz.send(msg, new OutputChannel[Any] {
+ val ftch = new Channel[A](Actor.self(scheduler))
+ send(msg, new OutputChannel[Any] {
def !(msg: Any) =
ftch ! handler(msg)
def send(msg: Any, replyTo: OutputChannel[Any]) =
@@ -54,85 +50,8 @@ private[actors] trait ActorCanReply extends ReactorCanReply {
}
override def !!(msg: Any): Future[Any] = {
- val ftch = new Channel[Any](Actor.self(thiz.scheduler))
- val linkedChannel = new AbstractActor {
- def !(msg: Any) = {
- ftch ! msg
- thiz unlinkFrom this
- }
- def send(msg: Any, replyTo: OutputChannel[Any]) = {
- ftch.send(msg, replyTo)
- thiz unlinkFrom this
- }
- def forward(msg: Any) = {
- ftch.forward(msg)
- thiz unlinkFrom this
- }
- def receiver =
- ftch.receiver
- def linkTo(to: AbstractActor) { /* do nothing */ }
- def unlinkFrom(from: AbstractActor) { /* do nothing */ }
- def exit(from: AbstractActor, reason: AnyRef) {
- ftch.send(Exit(from, reason), thiz)
- thiz unlinkFrom this
- }
- // should never be invoked; return dummy value
- def !?(msg: Any) = msg
- // should never be invoked; return dummy value
- def !?(msec: Long, msg: Any): Option[Any] = Some(msg)
- // should never be invoked; return dummy value
- override def !!(msg: Any): Future[Any] = {
- val someChan = new Channel[Any](Actor.self(thiz.scheduler))
- Futures.fromInputChannel(someChan)
- }
- // should never be invoked; return dummy value
- override def !![A](msg: Any, f: PartialFunction[Any, A]): Future[A] = {
- val someChan = new Channel[A](Actor.self(thiz.scheduler))
- Futures.fromInputChannel(someChan)
- }
- }
- thiz linkTo linkedChannel
- thiz.send(msg, linkedChannel)
- new Future[Any](ftch) {
- var exitReason: Option[Any] = None
- val handleReply: PartialFunction[Any, Unit] = {
- case Exit(from, reason) =>
- exitReason = Some(reason)
- case any =>
- fvalue = Some(any)
- }
-
- def apply(): Any =
- if (isSet) {
- if (!fvalue.isEmpty)
- fvalue.get
- else if (!exitReason.isEmpty) {
- val reason = exitReason.get
- if (reason.isInstanceOf[Throwable])
- throw new ExecutionException(reason.asInstanceOf[Throwable])
- else
- throw new ExecutionException(new Exception(reason.toString()))
- }
- } else inputChannel.receive(handleReply andThen { _ => apply() })
-
- def respond(k: Any => Unit): Unit =
- if (isSet)
- apply()
- else
- inputChannel.react(handleReply andThen { _ => k(apply()) })
-
- def isSet = (fvalue match {
- case None =>
- val handleTimeout: PartialFunction[Any, Boolean] = {
- case TIMEOUT =>
- false
- }
- val whatToDo =
- handleTimeout orElse (handleReply andThen { _ => true })
- inputChannel.receiveWithin(0)(whatToDo)
- case Some(_) => true
- }) || !exitReason.isEmpty
- }
+ val noTransform: PartialFunction[Any, Any] = { case x => x }
+ this !! (msg, noTransform)
}
}
diff --git a/src/actors/scala/actors/ActorTask.scala b/src/actors/scala/actors/ActorTask.scala
index 2fa24f93af..249c3784a4 100644
--- a/src/actors/scala/actors/ActorTask.scala
+++ b/src/actors/scala/actors/ActorTask.scala
@@ -25,24 +25,31 @@ private[actors] class ActorTask(actor: Actor,
protected override def beginExecution() {
super.beginExecution()
- if (actor.shouldExit)
- actor.exit()
+ actor.synchronized { // shouldExit guarded by actor
+ if (actor.shouldExit)
+ actor.exit()
+ }
}
- protected override def terminateExecution(e: Exception) {
+ protected override def terminateExecution(e: Throwable) {
val senderInfo = try { Some(actor.sender) } catch {
case _: Exception => None
}
- val uncaught = new UncaughtException(actor,
- if (msg != null) Some(msg) else None,
- senderInfo,
- currentThread,
- e)
+ val uncaught = UncaughtException(actor,
+ if (msg != null) Some(msg) else None,
+ senderInfo,
+ currentThread,
+ e)
- actor.synchronized {
+ val todo = actor.synchronized {
if (!actor.links.isEmpty)
- actor exitLinked uncaught
+ actor.exitLinked(uncaught)
+ else {
+ super.terminateExecution(e)
+ () => {}
+ }
}
+ todo()
}
}
diff --git a/src/actors/scala/actors/CanReply.scala b/src/actors/scala/actors/CanReply.scala
index 99e1169900..034eea8479 100644
--- a/src/actors/scala/actors/CanReply.scala
+++ b/src/actors/scala/actors/CanReply.scala
@@ -19,6 +19,8 @@ package scala.actors
*/
trait CanReply[-T, +R] {
+ type Future[+P] <: () => P
+
/**
* Sends <code>msg</code> to this $actor and
* awaits reply (synchronous).
@@ -47,8 +49,7 @@ trait CanReply[-T, +R] {
* @param msg the message to be sent
* @return the future
*/
- def !!(msg: T): () => R =
- () => this !? msg
+ def !!(msg: T): Future[R]
/**
* Sends <code>msg</code> to this $actor and
@@ -61,7 +62,6 @@ trait CanReply[-T, +R] {
* @param handler the function to be applied to the response
* @return the future
*/
- def !![P](msg: T, handler: PartialFunction[R, P]): () => P =
- () => handler(this !? msg)
+ def !![P](msg: T, handler: PartialFunction[R, P]): Future[P]
}
diff --git a/src/actors/scala/actors/Channel.scala b/src/actors/scala/actors/Channel.scala
index e40a804e4a..bf5d9261db 100644
--- a/src/actors/scala/actors/Channel.scala
+++ b/src/actors/scala/actors/Channel.scala
@@ -11,19 +11,18 @@
package scala.actors
-/** <p>
- * This class is used to pattern match on values that were sent
- * to some channel <code>Chan<sub>n</sub></code> by the current
- * actor <code>self</code>.
- * </p>
- * <p>
- * The following example demonstrates its usage:
- * </p><pre>
+/**
+ * This class is used to pattern match on values that were sent
+ * to some channel <code>Chan<sub>n</sub></code> by the current
+ * actor <code>self</code>.
+ *
+ * The following example demonstrates its usage:
+ * {{{
* receive {
* <b>case</b> Chan1 ! msg1 => ...
* <b>case</b> Chan2 ! msg2 => ...
* }
- * </pre>
+ * }}}
*
* @author Philipp Haller
*/
@@ -41,6 +40,8 @@ case class ! [a](ch: Channel[a], msg: a)
*/
class Channel[Msg](val receiver: Actor) extends InputChannel[Msg] with OutputChannel[Msg] with CanReply[Msg, Any] {
+ type Future[+P] = scala.actors.Future[P]
+
def this() = this(Actor.self)
def !(msg: Msg) {
@@ -109,4 +110,24 @@ class Channel[Msg](val receiver: Actor) extends InputChannel[Msg] with OutputCha
}
}
+ def !![A](msg: Msg, handler: PartialFunction[Any, A]): Future[A] = {
+ val ftch = new Channel[A](Actor.self(receiver.scheduler))
+ receiver.send(scala.actors.!(this, msg), new OutputChannel[Any] {
+ def !(msg: Any) =
+ ftch ! handler(msg)
+ def send(msg: Any, replyTo: OutputChannel[Any]) =
+ ftch.send(handler(msg), replyTo)
+ def forward(msg: Any) =
+ ftch.forward(handler(msg))
+ def receiver =
+ ftch.receiver
+ })
+ Futures.fromInputChannel(ftch)
+ }
+
+ def !!(msg: Msg): Future[Any] = {
+ val noTransform: PartialFunction[Any, Any] = { case x => x }
+ this !! (msg, noTransform)
+ }
+
}
diff --git a/src/actors/scala/actors/Reactor.scala b/src/actors/scala/actors/Reactor.scala
index 85dcd57189..fe00e216d3 100644
--- a/src/actors/scala/actors/Reactor.scala
+++ b/src/actors/scala/actors/Reactor.scala
@@ -84,6 +84,10 @@ trait Reactor[Msg >: Null] extends OutputChannel[Msg] with Combinators {
*/
def act(): Unit
+ /**
+ * This partial function is applied to exceptions that propagate out of
+ * this $actor's body.
+ */
protected[actors] def exceptionHandler: PartialFunction[Exception, Unit] =
Map()
diff --git a/src/actors/scala/actors/ReactorCanReply.scala b/src/actors/scala/actors/ReactorCanReply.scala
index 9002a55b87..e279845c9b 100644
--- a/src/actors/scala/actors/ReactorCanReply.scala
+++ b/src/actors/scala/actors/ReactorCanReply.scala
@@ -19,6 +19,8 @@ package scala.actors
private[actors] trait ReactorCanReply extends CanReply[Any, Any] {
_: ReplyReactor =>
+ override type Future[+P] = scala.actors.Future[P]
+
def !?(msg: Any): Any =
(this !! msg)()
@@ -39,10 +41,10 @@ private[actors] trait ReactorCanReply extends CanReply[Any, Any] {
res.get(msec)
}
- override def !!(msg: Any): Future[Any] =
+ def !!(msg: Any): Future[Any] =
this !! (msg, { case x => x })
- override def !![A](msg: Any, handler: PartialFunction[Any, A]): Future[A] = {
+ def !![A](msg: Any, handler: PartialFunction[Any, A]): Future[A] = {
val myself = Actor.rawSelf(this.scheduler)
val ftch = new ReactChannel[A](myself)
val res = new scala.concurrent.SyncVar[A]
diff --git a/src/actors/scala/actors/ReactorTask.scala b/src/actors/scala/actors/ReactorTask.scala
index 3f9ebb6fa7..c379334f2f 100644
--- a/src/actors/scala/actors/ReactorTask.scala
+++ b/src/actors/scala/actors/ReactorTask.scala
@@ -31,17 +31,16 @@ private[actors] class ReactorTask[Msg >: Null](var reactor: Reactor[Msg],
try {
beginExecution()
try {
- try {
- if (fun eq null)
- handler(msg)
- else
- fun()
- } catch {
- case e: Exception if (reactor.exceptionHandler.isDefinedAt(e)) =>
- reactor.exceptionHandler(e)
- }
+ if (fun eq null)
+ handler(msg)
+ else
+ fun()
} catch {
case _: KillActorControl =>
+ // do nothing
+
+ case e: Exception if reactor.exceptionHandler.isDefinedAt(e) =>
+ reactor.exceptionHandler(e)
}
reactor.kill()
}
@@ -49,17 +48,11 @@ private[actors] class ReactorTask[Msg >: Null](var reactor: Reactor[Msg],
case _: SuspendActorControl =>
// do nothing (continuation is already saved)
- case e: Exception =>
- // print message on default error stream
- val msgException = "Uncaught exception in "+reactor+"\n"
- val msgMessage = if (msg != null) "Message: "+msg+"\n" else ""
- Debug.doWarning {
- Console.err.print(msgException + msgMessage)
- e.printStackTrace()
- }
-
+ case e: Throwable =>
terminateExecution(e)
reactor.terminated()
+ if (!e.isInstanceOf[Exception])
+ throw e
} finally {
suspendExecution()
this.reactor = null
@@ -77,6 +70,9 @@ private[actors] class ReactorTask[Msg >: Null](var reactor: Reactor[Msg],
protected def suspendExecution() {}
- protected def terminateExecution(e: Exception) {}
+ protected def terminateExecution(e: Throwable) {
+ Console.err.println(reactor+": caught "+e)
+ e.printStackTrace()
+ }
}
diff --git a/src/actors/scala/actors/UncaughtException.scala b/src/actors/scala/actors/UncaughtException.scala
index 54c28f66cf..2b61b1ad7a 100644
--- a/src/actors/scala/actors/UncaughtException.scala
+++ b/src/actors/scala/actors/UncaughtException.scala
@@ -13,17 +13,18 @@ package scala.actors
*
* @param actor the actor that threw the exception
* @param message the message the actor was processing, or None if no message (e.g. on initial startup)
+ * @param sender the sender of the most recent message
* @param thread the thread on which the actor was running
* @param cause the uncaught exception
*
* @author Philipp Haller
* @author Erik Engbrecht
*/
-class UncaughtException[Msg >: Null](val actor: Reactor[Msg],
- val message: Option[Msg],
- val sender: Option[OutputChannel[Any]],
- val thread: Thread,
- cause: Exception)
+case class UncaughtException(actor: Actor,
+ message: Option[Any],
+ sender: Option[OutputChannel[Any]],
+ thread: Thread,
+ cause: Throwable)
extends Exception(cause) {
override def toString() =
diff --git a/src/actors/scala/actors/remote/Proxy.scala b/src/actors/scala/actors/remote/Proxy.scala
index f9a6cd8fed..ac5951ed85 100644
--- a/src/actors/scala/actors/remote/Proxy.scala
+++ b/src/actors/scala/actors/remote/Proxy.scala
@@ -20,8 +20,6 @@ import scala.collection.mutable.HashMap
private[remote] class Proxy(node: Node, name: Symbol, @transient var kernel: NetKernel) extends AbstractActor {
import java.io.{IOException, ObjectOutputStream, ObjectInputStream}
- type Future[+R] = scala.actors.Future[R]
-
@transient
private[remote] var del: Actor = null
startDelegate()
@@ -66,10 +64,10 @@ private[remote] class Proxy(node: Node, name: Symbol, @transient var kernel: Net
def !?(msec: Long, msg: Any): Option[Any] =
del !? (msec, msg)
- override def !!(msg: Any): Future[Any] =
+ def !!(msg: Any): Future[Any] =
del !! msg
- override def !![A](msg: Any, f: PartialFunction[Any, A]): Future[A] =
+ def !![A](msg: Any, f: PartialFunction[Any, A]): Future[A] =
del !! (msg, f)
def linkTo(to: AbstractActor): Unit =
diff --git a/src/actors/scala/actors/remote/RemoteActor.scala b/src/actors/scala/actors/remote/RemoteActor.scala
index 860ff3bfe3..78361ec0fb 100644
--- a/src/actors/scala/actors/remote/RemoteActor.scala
+++ b/src/actors/scala/actors/remote/RemoteActor.scala
@@ -13,33 +13,30 @@ package scala.actors
package remote
-/** <p>
- * This object provides methods for creating, registering, and
- * selecting remotely accessible actors.
- * </p>
- * <p>
- * A remote actor is typically created like this:
- * </p><pre>
+/**
+ * This object provides methods for creating, registering, and
+ * selecting remotely accessible actors.
+ *
+ * A remote actor is typically created like this:
+ * {{{
* actor {
* alive(9010)
* register('myName, self)
*
* // behavior
* }
- * </pre>
- * <p>
- * It can be accessed by an actor running on a (possibly)
- * different node by selecting it in the following way:
- * </p><pre>
+ * }}}
+ * It can be accessed by an actor running on a (possibly)
+ * different node by selecting it in the following way:
+ * {{{
* actor {
* // ...
- * <b>val</b> c = select(Node("127.0.0.1", 9010), 'myName)
+ * val c = select(Node("127.0.0.1", 9010), 'myName)
* c ! msg
* // ...
* }
- * </pre>
+ * }}}
*
- * @version 0.9.18
* @author Philipp Haller
*/
object RemoteActor {
diff --git a/src/build/pack.xml b/src/build/pack.xml
index fa6c4ade20..d75e36c337 100644
--- a/src/build/pack.xml
+++ b/src/build/pack.xml
@@ -120,9 +120,10 @@ MAIN DISTRIBUTION SBAZ
<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"/>
+ 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/**/*.test"/>
<!-- <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>
diff --git a/src/compiler/scala/tools/cmd/CommandLine.scala b/src/compiler/scala/tools/cmd/CommandLine.scala
index 8cb4c00b14..9b8bef4a9a 100644
--- a/src/compiler/scala/tools/cmd/CommandLine.scala
+++ b/src/compiler/scala/tools/cmd/CommandLine.scala
@@ -8,18 +8,19 @@ package cmd
import scala.collection.mutable.ListBuffer
+trait CommandLineConfig {
+ def enforceArity: Boolean = true
+ def onlyKnownOptions: Boolean = true
+}
+
/** An instance of a command line, parsed according to a Spec.
*/
-class CommandLine(val spec: Reference, val originalArgs: List[String]) {
+class CommandLine(val spec: Reference, val originalArgs: List[String]) extends CommandLineConfig {
def this(spec: Reference, line: String) = this(spec, Parser tokenize line)
def this(spec: Reference, args: Array[String]) = this(spec, args.toList)
import spec.{ isAnyOption, isUnaryOption, isBinaryOption, isExpandOption }
- def assumeBinary = true
- def enforceArity = true
- def onlyKnownOptions = false
-
val Terminator = "--"
val ValueForUnaryOption = "true" // so if --opt is given, x(--opt) = true
@@ -32,13 +33,6 @@ class CommandLine(val spec: Reference, val originalArgs: List[String]) {
lazy val (argMap, residualArgs) = {
val residualBuffer = new ListBuffer[String]
- def isOption(s: String) = isAnyOption(s) || ((s startsWith "-") && !onlyKnownOptions)
-
- def unknownOption(opt: String) =
- errorFn("Option '%s' not recognized.".format(opt))
- def missingArg(opt: String, what: String) =
- errorFn("Option '%s' requires argument, found %s instead.".format(opt, what))
-
def loop(args: List[String]): Map[String, String] = {
def residual(xs: List[String]) = { residualBuffer ++= xs ; Map[String, String]() }
@@ -54,22 +48,32 @@ class CommandLine(val spec: Reference, val originalArgs: List[String]) {
else None
}
+ /** Assumes known options have all been ruled out already. */
+ def isUnknown(opt: String) =
+ onlyKnownOptions && (opt startsWith "-") && {
+ errorFn("Option '%s' not recognized.".format(opt))
+ true
+ }
+
args match {
case Nil => Map()
case Terminator :: xs => residual(xs)
case x :: Nil =>
expand(x) foreach (exp => return loop(exp))
if (isBinaryOption(x) && enforceArity)
- missingArg(x, "EOF")
+ errorFn("Option '%s' requires argument, found EOF instead.".format(x))
if (isUnaryOption(x)) mapForUnary(x)
+ else if (isUnknown(x)) Map()
else residual(args)
+
case x1 :: x2 :: xs =>
expand(x1) foreach (exp => return loop(exp ++ args.tail))
if (x2 == Terminator) mapForUnary(x1) ++ residual(xs)
else if (isUnaryOption(x1)) mapForUnary(x1) ++ loop(args.tail)
else if (isBinaryOption(x1)) Map(x1 -> x2) ++ loop(xs)
+ else if (isUnknown(x1)) loop(args.tail)
else residual(List(x1)) ++ loop(args.tail)
}
}
@@ -85,23 +89,3 @@ class CommandLine(val spec: Reference, val originalArgs: List[String]) {
override def toString() = argMap.toString + " " + residualArgs.toString
}
-
-object CommandLine {
- def apply(args: List[String], unary: List[String], binary: List[String]) = {
- /** XXX Temporarily assembling a fake spec so we can continue to
- * do ad-hoc parsing based on a list of unary and binary args.
- * Should either clean this up or do it differently.
- */
- object NoSpec extends Reference {
- unary foreach (_ --? )
- binary foreach (_ --| )
-
- protected def creator(args: List[String]) = error("No Spec")
- def programInfo = Spec.Names("", "")
- lazy val referenceSpec = this
- }
-
- new CommandLine(NoSpec, args)
- }
-}
-
diff --git a/src/compiler/scala/tools/cmd/Demo.scala b/src/compiler/scala/tools/cmd/Demo.scala
index 7014e6b4d7..22cf50bd58 100644
--- a/src/compiler/scala/tools/cmd/Demo.scala
+++ b/src/compiler/scala/tools/cmd/Demo.scala
@@ -10,7 +10,7 @@ package cmd
* First take advantage of the meta-options:
*
* // this command creates an executable runner script "demo"
- * % scala scala.tools.cmd.Demo --generate-runner demo
+ * % scala scala.tools.cmd.Demo --self-update demo
*
* // this one creates and sources a completion file - note backticks
* % `./demo --bash`
@@ -19,13 +19,13 @@ package cmd
* % ./demo --<tab>
* --action --defint --int
* --bash --defstr --str
- * --defenv --generate-runner --unary
+ * --defenv --self-update --unary
*
* The normal option configuration is plausibly self-explanatory.
*/
trait DemoSpec extends Spec with Meta.StdOpts with Interpolation {
lazy val referenceSpec = DemoSpec
- lazy val programInfo = Spec.Names("demo", "scala.tools.cmd.Demo")
+ lazy val programInfo = Spec.Info("demo", "Usage: demo [<options>]", "scala.tools.cmd.Demo")
help("""Usage: demo [<options>]""")
heading("Unary options:")
@@ -48,7 +48,6 @@ object DemoSpec extends DemoSpec with Property {
type ThisCommandLine = SpecCommandLine
def creator(args: List[String]) =
new SpecCommandLine(args) {
- override def onlyKnownOptions = true
override def errorFn(msg: String) = { println("Error: " + msg) ; System.exit(0) }
}
}
diff --git a/src/compiler/scala/tools/cmd/Instance.scala b/src/compiler/scala/tools/cmd/Instance.scala
index 4d319b98cc..3c0dbbaa1f 100644
--- a/src/compiler/scala/tools/cmd/Instance.scala
+++ b/src/compiler/scala/tools/cmd/Instance.scala
@@ -16,7 +16,8 @@ trait Instance extends Spec {
protected def help(str: => String): Unit = ()
def isSet(s: String) = parsed isSet toOpt(s)
- def originalArgs = parsed.originalArgs
+ def originalArgs = parsed.originalArgs // the full original list
+ def residualArgs = parsed.residualArgs // only args which were not options or args to options
type OptionMagic = Opt.Instance
protected implicit def optionMagicAdditions(name: String) = new Opt.Instance(programInfo, parsed, name)
diff --git a/src/compiler/scala/tools/cmd/Interpolation.scala b/src/compiler/scala/tools/cmd/Interpolation.scala
index 6b86a35bb9..a326d48f64 100644
--- a/src/compiler/scala/tools/cmd/Interpolation.scala
+++ b/src/compiler/scala/tools/cmd/Interpolation.scala
@@ -52,8 +52,6 @@ object Interpolation {
|#!/bin/sh
|#
|
- |scala @@MAINCLASS@@ $*
- |
- """.stripMargin
+ |scala @@MAINCLASS@@ "$@"
+ |""".stripMargin.trim + "\n"
}
-
diff --git a/src/compiler/scala/tools/cmd/Meta.scala b/src/compiler/scala/tools/cmd/Meta.scala
index 5a09766b13..8609db3d50 100644
--- a/src/compiler/scala/tools/cmd/Meta.scala
+++ b/src/compiler/scala/tools/cmd/Meta.scala
@@ -22,11 +22,11 @@ object Meta {
trait StdOpts {
self: Spec with Interpolation =>
- Bash.name --> runAndExit(Bash.action())
- val runnerFileName = Runner.name --| ;
+ Bash.name --> runAndExit(Bash.action())
+ val selfUpdateName = SelfUpdate.name --| ;
- if (runnerFileName.isDefined)
- runAndExit(Runner.action())
+ if (selfUpdateName.isDefined)
+ runAndExit(SelfUpdate.action())
/** I think we're as close as we can get to bundling completion with
* the program given the constraints imposed by bash. This outputs
@@ -47,12 +47,17 @@ object Meta {
}
}
- /** A very basic runner script.
+ /** Generates a very basic runner script. It's called SelfUpdate
+ * because once it exists you can do something like
+ *
+ * tools/scmp --self-update tools/scmp
+ *
+ * and it will overwrite itself with the current version.
*/
- object Runner extends Opt {
- val name = "generate-runner"
+ object SelfUpdate extends Opt {
+ val name = "self-update"
val action = () => {
- val file = File(runnerFileName.get)
+ val file = File(selfUpdateName.get)
file writeAll interpolate(runnerTemplate)
file setExecutable true
()
diff --git a/src/compiler/scala/tools/cmd/Opt.scala b/src/compiler/scala/tools/cmd/Opt.scala
index 9e3c324deb..beea590492 100644
--- a/src/compiler/scala/tools/cmd/Opt.scala
+++ b/src/compiler/scala/tools/cmd/Opt.scala
@@ -7,7 +7,7 @@ package scala.tools
package cmd
import nsc.Properties.envOrElse
-import Spec.Names
+import Spec.Info
/** Machinery for what amounts to a command line specification DSL.
* It is designed so the same specification trait can be used for
@@ -25,7 +25,7 @@ object Opt {
trait Implicit {
def name: String
- def programInfo: Names
+ def programInfo: Info
protected def opt = toOpt(name)
def --? : Boolean // --opt is set
@@ -47,7 +47,7 @@ object Opt {
def /(descr: String): String // --opt has help description 'descr'
}
- class Reference(val programInfo: Names, val options: Reference.Accumulators, val name: String) extends Implicit {
+ class Reference(val programInfo: Info, val options: Reference.Accumulators, val name: String) extends Implicit {
import options._
def --? = { addUnary(opt) ; false }
@@ -63,7 +63,7 @@ object Opt {
def /(descr: String) = returning(name)(_ => addHelp(() => helpFormatStr.format(opt, descr)))
}
- class Instance(val programInfo: Names, val parsed: CommandLine, val name: String) extends Implicit with Error {
+ class Instance(val programInfo: Info, val parsed: CommandLine, val name: String) extends Implicit with Error {
def --? = parsed isSet opt
def --> (body: => Unit) = if (parsed isSet opt) body
def --| = parsed get opt
diff --git a/src/compiler/scala/tools/cmd/Reference.scala b/src/compiler/scala/tools/cmd/Reference.scala
index 695868191b..3f3712766b 100644
--- a/src/compiler/scala/tools/cmd/Reference.scala
+++ b/src/compiler/scala/tools/cmd/Reference.scala
@@ -32,7 +32,8 @@ trait Reference extends Spec {
protected def help(str: => String) = addHelp(() => str)
- type ThisCommandLine <: SpecCommandLine
+ type ThisCommandLine <: CommandLine
+
class SpecCommandLine(args: List[String]) extends CommandLine(Reference.this, args) { }
protected def creator(args: List[String]): ThisCommandLine
final def apply(args: String*): ThisCommandLine = creator(propertyArgs ++ args flatMap expandArg)
diff --git a/src/compiler/scala/tools/cmd/Spec.scala b/src/compiler/scala/tools/cmd/Spec.scala
index c8283165d9..794bb3303f 100644
--- a/src/compiler/scala/tools/cmd/Spec.scala
+++ b/src/compiler/scala/tools/cmd/Spec.scala
@@ -12,7 +12,7 @@ package cmd
*/
trait Spec {
def referenceSpec: Reference
- def programInfo: Spec.Names
+ def programInfo: Spec.Info
protected def help(str: => String): Unit
protected def heading(str: => String): Unit = help("\n " + str)
@@ -22,7 +22,14 @@ trait Spec {
}
object Spec {
- case class Names(runner: String, mainClass: String) { }
+ class Info(
+ val runner: String,
+ val usage: String,
+ val mainClass: String
+ )
+ object Info {
+ def apply(runner: String, help: String, mainClass: String): Info = new Info(runner, help, mainClass)
+ }
class Accumulator[T: FromString]() {
private var _buf: List[T] = Nil
diff --git a/src/compiler/scala/tools/cmd/program/Scmp.scala b/src/compiler/scala/tools/cmd/program/Scmp.scala
new file mode 100644
index 0000000000..ff4fa11eaf
--- /dev/null
+++ b/src/compiler/scala/tools/cmd/program/Scmp.scala
@@ -0,0 +1,59 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools
+package cmd
+package program
+
+import nsc.io._
+
+object Scmp {
+ private val scmpUsage = """
+ |Usage: scmp [options] <cmd line>
+ |Example: scmp --p1 '-no-specialization -Ydebug' scalac src/library/scala/Function1.scala
+ |
+ |Note: the command line must start with a path to scalac.
+ |""".stripMargin
+ private val scmpOptions = List(
+ "p1" -> "options for the first run only",
+ "p2" -> "options for the second run only"
+ )
+ private val scmpInfo = Simple.scalaProgramInfo("scmp", scmpUsage)
+ lazy val ScmpSpec = Simple(scmpInfo, Nil, scmpOptions, x => returning(x)(_.onlyKnownOptions = false))
+
+ def main(args0: Array[String]): Unit = {
+ if (args0.isEmpty)
+ return println(scmpUsage)
+
+ val runner = ScmpSpec instance args0
+ import runner._
+
+ val p1args = parsed.getOrElse("--p1", "")
+ val p2args = parsed.getOrElse("--p2", "")
+
+ if (p1args.isEmpty && p2args.isEmpty)
+ return println("At least one of --p1 and --p2 must be given.")
+ if (residualArgs.isEmpty)
+ return println("There is no command to run.")
+
+ def createCmd(extras: String) =
+ fromArgs(residualArgs.patch(1, toArgs(extras), 0))
+
+ def runCmd(cmd: String) = {
+ val output = Process(cmd, redirect = true).slurp()
+
+ returning(File.makeTemp())(_ writeAll output)
+ }
+
+ val cmds = List(p1args, p2args) map createCmd
+ println(cmds.mkString("Running command lines:\n ", "\n ", ""))
+
+ val files = cmds map runCmd map (_.path)
+ val diff = Process("diff %s %s".format(files: _*)).slurp()
+
+ if (diff.isEmpty) println("No differences.")
+ else println(diff)
+ }
+}
diff --git a/src/compiler/scala/tools/cmd/program/Simple.scala b/src/compiler/scala/tools/cmd/program/Simple.scala
new file mode 100644
index 0000000000..641be31c9e
--- /dev/null
+++ b/src/compiler/scala/tools/cmd/program/Simple.scala
@@ -0,0 +1,81 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools
+package cmd
+package program
+
+import Spec.Info
+
+/** A boilerplate reducer for commands with simple requirements. For examples,
+ * see Scmp and Tokens in this package.
+ */
+object Simple {
+ type CommandLineTransform = SimpleCommandLine => SimpleCommandLine
+
+ abstract class SimpleSpec(val programInfo: Info) extends Spec with Meta.StdOpts with Interpolation
+
+ trait SimpleInstance extends SimpleSpec with Instance {
+ val parsed: CommandLine
+ }
+
+ class SimpleReference(
+ programInfo: Info,
+ unary: List[(String, String)] = Nil,
+ binary: List[(String, String)] = Nil,
+ postCreation: CommandLineTransform = null
+ ) extends SimpleSpec(programInfo) with Reference {
+
+ spec =>
+
+ if (programInfo.usage != "") help(programInfo.usage)
+ unary foreach { case (option, help) => option / help --? }
+ binary foreach { case (option, help) => option / help --| }
+
+ type ThisCommandLine = SimpleCommandLine
+
+ def creator(args: List[String]) = new SimpleCommandLine(spec, args)
+ def instance(args: Array[String]): SimpleInstance = instance(args.toList)
+ def instance(args: List[String]): SimpleInstance =
+ new {
+ val parsed = spec(args: _*)
+ } with SimpleSpec(programInfo) with SimpleInstance {
+ lazy val referenceSpec = spec
+ }
+
+ lazy val referenceSpec = spec
+ }
+
+ def apply(info: Info, unary: List[(String, String)], binary: List[(String, String)], postCreation: CommandLineTransform): SimpleReference = {
+ new SimpleReference(info, unary, binary, postCreation) {
+ override def creator(args: List[String]) = {
+ val obj = super.creator(args)
+ if (postCreation == null) obj
+ else postCreation(obj)
+ }
+ }
+ }
+
+ def scalaProgramInfo(name: String, help: String) =
+ Spec.Info(name, help, "scala.tools.cmd.program." + name.capitalize)
+
+ /** You can't override a def with a var unless a setter exists. We cleverly
+ * sidestep this by mixing in a trait with dummy setters which will be
+ * inaccessible due to the overriding var.
+ */
+ trait Ticket2338WontFixWorkaround {
+ def enforceArity_=(x: Boolean): Unit = error("unreachable")
+ def onlyKnownOptions_=(x: Boolean): Unit = error("unreachable")
+ }
+
+ /** Configurability simplicity achieved by turning defs into vars and letting
+ * the spec creator apply a transformation. This way there's no need to create
+ * custom subclasses of CommandLine.
+ */
+ class SimpleCommandLine(spec: Reference, args: List[String]) extends CommandLine(spec, args) with Ticket2338WontFixWorkaround {
+ override var enforceArity: Boolean = true
+ override var onlyKnownOptions: Boolean = true
+ }
+}
diff --git a/src/compiler/scala/tools/cmd/program/Tokens.scala b/src/compiler/scala/tools/cmd/program/Tokens.scala
new file mode 100644
index 0000000000..36786aa2b7
--- /dev/null
+++ b/src/compiler/scala/tools/cmd/program/Tokens.scala
@@ -0,0 +1,100 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2010 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools
+package cmd
+package program
+
+import nsc._
+import util.Chars.char2uescape
+import io._
+import ast.parser.Tokens._
+
+/** Given paths on the command line, tokenizes any scala files found
+ * and prints one token per line.
+ */
+object Tokens {
+ private val tokensUsage = "Usage: tokens [options] <path1 path2 ...>\n\nOptions:"
+ private val tokensUnary = List(
+ "verbose" -> "be more verbose",
+ "freq" -> "combine token lists and sort by frequency",
+ "stats" -> "output some stats"
+ )
+ private val tokensBinary = List(
+ "sliding" -> "print tokens in groups of given size"
+ )
+ private val tokensInfo = Simple.scalaProgramInfo("tokens", tokensUsage)
+ private lazy val TokensSpec = Simple(tokensInfo, tokensUnary, tokensBinary, null)
+
+ def sanitize(x: Any): String = sanitize(x.toString)
+ def sanitize(str: String): String = str flatMap (x => if (x.isControl) char2uescape(x) else x.toString)
+
+ def main(args0: Array[String]): Unit = {
+ if (args0.isEmpty)
+ return println(TokensSpec.helpMsg)
+
+ val runner = TokensSpec instance args0
+ import runner._
+
+ val files = (residualArgs flatMap walk).distinct
+ if (parsed isSet "--verbose")
+ println("Tokenizing: " + (files map (_.name) mkString " "))
+
+ if (parsed isSet "--stats")
+ println("Stats not yet implemented.")
+
+ def raw = files flatMap fromScalaSource
+ def tokens: List[Any] =
+ if (parsed isSet "--sliding") raw sliding parsed("--sliding").toInt map (_ map sanitize mkString " ") toList
+ else raw
+
+ def output =
+ if (parsed isSet "--freq")
+ (tokens groupBy (x => x) mapValues (_.length)).toList sortBy (-_._2) map (x => x._2 + " " + x._1)
+ else
+ tokens
+
+ output foreach println
+ }
+
+ def fromPaths(paths: String*): List[Any] =
+ (paths.toList flatMap walk).distinct flatMap fromScalaSource
+
+ /** Given a path, returns all .scala files underneath it.
+ */
+ private def walk(arg: String): List[File] = {
+ def traverse = Path(arg) ifDirectory (_.deepList()) getOrElse Iterator(File(arg))
+
+ Path onlyFiles traverse filter (_ hasExtension "scala") toList
+ }
+
+ /** Tokenizes a single scala file.
+ */
+ def fromScalaSource(file: Path): List[Any] = fromScalaSource(file.path)
+ def fromScalaSource(file: String): List[Any] = {
+ val global = new Global(new Settings())
+ import global._
+ import syntaxAnalyzer.{ UnitScanner, token2string }
+
+ val in = new UnitScanner(new CompilationUnit(getSourceFile(file)))
+ in.init()
+
+ Iterator continually {
+ val token = in.token match {
+ case IDENTIFIER | BACKQUOTED_IDENT => in.name
+ case CHARLIT | INTLIT | LONGLIT => in.intVal
+ case DOUBLELIT | FLOATLIT => in.floatVal
+ case STRINGLIT => "\"" + in.strVal + "\""
+ case SEMI | NEWLINE => ";"
+ case NEWLINES => ";;"
+ case COMMA => ","
+ case EOF => null
+ case x => token2string(x)
+ }
+ in.nextToken()
+ token
+ } takeWhile (_ != null) toList
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 16bff5d399..0ec36cf9ab 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -137,7 +137,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
def error(msg: String) = reporter.error(NoPosition, msg)
def warning(msg: String) =
- if (settings.Ywarnfatal.value) reporter.error(NoPosition, msg)
+ if (settings.Xwarnfatal.value) reporter.error(NoPosition, msg)
else reporter.warning(NoPosition, msg)
def inform(msg: String) = reporter.info(NoPosition, msg, true)
def inform[T](msg: String, value: T): T = { inform(msg+value); value }
@@ -714,7 +714,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
/** Compile list of source files */
def compileSources(_sources: List[SourceFile]) {
val depSources = dependencyAnalysis.filter(_sources.distinct) // bug #1268, scalac confused by duplicated filenames
- val sources = scalaObjectFirst(depSources)
+ val sources = coreClassesFirst(depSources)
if (reporter.hasErrors)
return // there is a problem already, e.g. a
// plugin was passed a bad option
@@ -871,14 +871,43 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
if (!pclazz.isRoot) resetPackageClass(pclazz.owner)
}
- private def scalaObjectFirst(files: List[SourceFile]) = {
+ /**
+ * Re-orders the source files to
+ * 1. ScalaObject
+ * 2. LowPriorityImplicits / StandardEmbeddings (i.e. parents of Predef)
+ * 3. the rest
+ *
+ * 1 is to avoid cyclic reference errors.
+ * 2 is due to the following. When completing "Predef" (*), typedIdent is called
+ * for its parents (e.g. "LowPriorityImplicits"). typedIdent checks wethter
+ * the symbol reallyExists, which tests if the type of the symbol after running
+ * its completer is != NoType.
+ * If the "namer" phase has not yet run for "LowPriorityImplicits", the symbol
+ * has a SourcefileLoader as type. Calling "doComplete" on it does nothing at
+ * all, because the source file is part of the files to be compiled anyway.
+ * So the "reallyExists" test will return "false".
+ * Only after the namer, the symbol has a lazy type which actually computes
+ * the info, and "reallyExists" behaves as expected.
+ * So we need to make sure that the "namer" phase is run on predef's parents
+ * before running it on predef.
+ *
+ * (*) Predef is completed early when calling "mkAttributedRef" during the
+ * addition of "import Predef._" to sourcefiles. So this situation can't
+ * happen for user classes.
+ *
+ */
+ private def coreClassesFirst(files: List[SourceFile]) = {
def inScalaFolder(f: SourceFile) =
f.file.container.name == "scala"
+ var scalaObject: Option[SourceFile] = None
val res = new ListBuffer[SourceFile]
for (file <- files) file.file.name match {
- case "ScalaObject.scala" if inScalaFolder(file) => file +=: res
+ case "ScalaObject.scala" if inScalaFolder(file) => scalaObject = Some(file)
+ case "LowPriorityImplicits.scala" if inScalaFolder(file) => file +=: res
+ case "StandardEmbeddings.scala" if inScalaFolder(file) => file +=: res
case _ => res += file
}
+ for (so <- scalaObject) so +=: res
res.toList
}
} // class Run
diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala
index 0cc0f65640..556a3107cd 100644
--- a/src/compiler/scala/tools/nsc/Interpreter.scala
+++ b/src/compiler/scala/tools/nsc/Interpreter.scala
@@ -27,7 +27,7 @@ import scala.util.control.Exception.{ Catcher, catching, ultimately, unwrapping
import io.{ PlainFile, VirtualDirectory }
import reporters.{ ConsoleReporter, Reporter }
import symtab.{ Flags, Names }
-import util.{ SourceFile, BatchSourceFile, ClassPath }
+import util.{ SourceFile, BatchSourceFile, ClassPath, Chars }
import scala.reflect.NameTransformer
import scala.tools.nsc.{ InterpreterResults => IR }
import interpreter._
@@ -74,6 +74,8 @@ import Interpreter._
* @author Lex Spoon
*/
class Interpreter(val settings: Settings, out: PrintWriter) {
+ repl =>
+
/** construct an interpreter that reports to Console */
def this(settings: Settings) = this(settings, new NewLinePrintWriter(new ConsoleWriter, true))
def this() = this(new Settings())
@@ -236,6 +238,12 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
private val boundNameMap = new HashMap[Name, Request]()
private def allHandlers = prevRequests.toList flatMap (_.handlers)
+ def printAllTypeOf = {
+ prevRequests foreach { req =>
+ req.typeOf foreach { case (k, v) => Console.println(k + " => " + v) }
+ }
+ }
+
/** Most recent tree handled which wasn't wholly synthetic. */
private def mostRecentlyHandledTree: Option[Tree] = {
for {
@@ -487,42 +495,6 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
}
}
- /** For :power - create trees and type aliases from code snippets. */
- def mkContext(code: String = "") = compiler.analyzer.rootContext(mkUnit(code))
- def mkAlias(name: String, what: String) = interpret("type %s = %s".format(name, what))
- def mkSourceFile(code: String) = new BatchSourceFile("<console>", code)
- def mkUnit(code: String) = new CompilationUnit(mkSourceFile(code))
-
- def mkTree(code: String): Tree = mkTrees(code).headOption getOrElse EmptyTree
- def mkTrees(code: String): List[Tree] = parse(code) getOrElse Nil
- def mkTypedTrees(code: String*): List[compiler.Tree] = {
- class TyperRun extends compiler.Run {
- override def stopPhase(name: String) = name == "superaccessors"
- }
-
- reporter.reset
- val run = new TyperRun
- run compileSources (code.toList.zipWithIndex map {
- case (s, i) => new BatchSourceFile("<console %d>".format(i), s)
- })
- run.units.toList map (_.body)
- }
- def mkTypedTree(code: String) = mkTypedTrees(code).head
-
- def mkType(id: String): compiler.Type = {
- // if it's a recognized identifier, the type of that; otherwise treat the
- // String like it is itself a type (e.g. scala.collection.Map) .
- val typeName = typeForIdent(id) getOrElse id
-
- try definitions.getClass(newTermName(typeName)).tpe
- catch { case _: Throwable => NoType }
- }
-
- private[nsc] val powerMkImports = List(
- "mkContext", "mkTree", "mkTrees", "mkAlias", "mkSourceFile", "mkUnit", "mkType", "mkTypedTree", "mkTypedTrees"
- // , "treeWrapper"
- )
-
/** Compile an nsc SourceFile. Returns true if there are
* no compilation errors, or false otherwise.
*/
@@ -796,16 +768,32 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
}
private class ImportHandler(imp: Import) extends MemberHandler(imp) {
+ lazy val Import(expr, selectors) = imp
+ def targetType = stringToCompilerType(expr.toString) match {
+ case NoType => None
+ case x => Some(x)
+ }
+
+ private def selectorWild = selectors filter (_.name == USCOREkw) // wildcard imports, e.g. import foo._
+ private def selectorMasked = selectors filter (_.rename == USCOREkw) // masking imports, e.g. import foo.{ bar => _ }
+ private def selectorNames = selectors map (_.name)
+ private def selectorRenames = selectors map (_.rename) filterNot (_ == null)
+
/** Whether this import includes a wildcard import */
- val importsWildcard = imp.selectors map (_.name) contains USCOREkw
+ val importsWildcard = selectorWild.nonEmpty
+
+ /** Complete list of names imported by a wildcard */
+ def wildcardImportedNames: List[Name] = (
+ for (tpe <- targetType ; if importsWildcard) yield
+ tpe.nonPrivateMembers filter (x => x.isMethod && x.isPublic) map (_.name) distinct
+ ).toList.flatten
/** The individual names imported by this statement */
- val importedNames: List[Name] = (
- imp.selectors
- . map (x => x.rename)
- . filter (x => x != null && x != USCOREkw)
- . flatMap (x => List(x.toTypeName, x.toTermName))
- )
+ /** XXX come back to this and see what can be done with wildcards now that
+ * we know how to enumerate the identifiers.
+ */
+ val importedNames: List[Name] =
+ selectorRenames filterNot (_ == USCOREkw) flatMap (x => List(x.toTypeName, x.toTermName))
override def resultExtractionCode(req: Request, code: PrintWriter) =
code println codegenln(imp.toString)
@@ -830,9 +818,10 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
/** def and val names */
def defNames = partialFlatMap(handlers) { case x: DefHandler => x.boundNames }
- def valAndVarNames = partialFlatMap(handlers) {
+ def valueNames = partialFlatMap(handlers) {
case x: AssignHandler => List(x.helperName)
case x: ValHandler => boundNames
+ case x: ModuleHandler => List(x.name)
}
/** Code to import bound names from previous lines - accessPath is code to
@@ -940,7 +929,6 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
!reporter.hasErrors
}
-
def atNextPhase[T](op: => T): T = compiler.atPhase(objRun.typerPhase.next)(op)
/** The outermost wrapper object */
@@ -972,7 +960,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
}
}
- getTypes(valAndVarNames, nme.getterToLocal(_)) ++ getTypes(defNames, identity)
+ getTypes(valueNames, nme.getterToLocal(_)) ++ getTypes(defNames, identity)
}
/** load and run the code using reflection */
@@ -999,43 +987,64 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
}
}
- /** These methods are exposed so REPL commands can access them.
- * The command infrastructure is in InterpreterLoop.
+ /** A container class for methods to be injected into the repl
+ * in power mode.
*/
- def dumpState(xs: List[String]): String = """
- | Names used: %s
- |
- | Identifiers: %s
- |
- | synthvars: %d
- """.stripMargin.format(
- allUsedNames mkString " ",
- unqualifiedIds mkString " ",
- allBoundNames filter isSynthVarName size
- )
-
- // def dumpTrees(xs: List[String]): String = {
- // val treestrs = (xs map requestForIdent).flatten flatMap (_.trees)
- //
- // if (treestrs.isEmpty) "No trees found."
- // else treestrs.map(t => t.toString + " (" + t.getClass.getSimpleName + ")\n").mkString
- // }
+ object power {
+ lazy val compiler: repl.compiler.type = repl.compiler
+ import compiler.{ phaseNames, atPhase, currentRun }
+
+ def mkContext(code: String = "") = compiler.analyzer.rootContext(mkUnit(code))
+ def mkAlias(name: String, what: String) = interpret("type %s = %s".format(name, what))
+ def mkSourceFile(code: String) = new BatchSourceFile("<console>", code)
+ def mkUnit(code: String) = new CompilationUnit(mkSourceFile(code))
+
+ def mkTree(code: String): Tree = mkTrees(code).headOption getOrElse EmptyTree
+ def mkTrees(code: String): List[Tree] = parse(code) getOrElse Nil
+ def mkTypedTrees(code: String*): List[compiler.Tree] = {
+ class TyperRun extends compiler.Run {
+ override def stopPhase(name: String) = name == "superaccessors"
+ }
- def powerUser(): String = {
- beQuietDuring {
- this.bind("repl", "scala.tools.nsc.Interpreter", this)
- this.bind("global", "scala.tools.nsc.Global", compiler)
- interpret("import repl.{ %s, eval }".format(powerMkImports mkString ", "), false)
+ reporter.reset
+ val run = new TyperRun
+ run compileSources (code.toList.zipWithIndex map {
+ case (s, i) => new BatchSourceFile("<console %d>".format(i), s)
+ })
+ run.units.toList map (_.body)
}
+ def mkTypedTree(code: String) = mkTypedTrees(code).head
+ def mkType(id: String): compiler.Type = stringToCompilerType(id)
+
+ def dump(): String = (
+ ("Names used: " :: allUsedNames) ++
+ ("\nIdentifiers: " :: unqualifiedIds)
+ ) mkString " "
+
+ lazy val allPhases: List[Phase] = phaseNames map (currentRun phaseNamed _)
+ def atAllPhases[T](op: => T): List[(String, T)] = allPhases map (ph => (ph.name, atPhase(ph)(op)))
+ def showAtAllPhases(op: => Any): Unit =
+ atAllPhases(op.toString) foreach { case (ph, op) => Console.println("%15s -> %s".format(ph, op take 240)) }
+ }
- """** Power User mode enabled - BEEP BOOP **
- |** New vals! Try repl, global **
- |** New cmds! :help to discover them **
- |** New defs! Give these a whirl: **
- |** mkAlias("Fn", "(String, Int) => Int") **
- |** mkTree("def f(x: Int, y: Int) = x+y") **""".stripMargin
+ def unleash(): Unit = beQuietDuring {
+ interpret("import scala.tools.nsc._")
+ repl.bind("repl", "scala.tools.nsc.Interpreter", this)
+ interpret("val global: repl.compiler.type = repl.compiler")
+ interpret("val power: repl.power.type = repl.power")
+ // interpret("val replVars = repl.replVars")
}
+ /** Artificial object demonstrating completion */
+ // lazy val replVars = CompletionAware(
+ // Map[String, CompletionAware](
+ // "ids" -> CompletionAware(() => unqualifiedIds, completionAware _),
+ // "synthVars" -> CompletionAware(() => allBoundNames filter isSynthVarName map (_.toString)),
+ // "types" -> CompletionAware(() => allSeenTypes map (_.toString)),
+ // "implicits" -> CompletionAware(() => allImplicits map (_.toString))
+ // )
+ // )
+
/** Returns the name of the most recent interpreter result.
* Mostly this exists so you can conveniently invoke methods on
* the previous result.
@@ -1052,11 +1061,21 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
private def requestForName(name: Name): Option[Request] =
prevRequests.reverse find (_.boundNames contains name)
- private def requestForIdent(line: String): Option[Request] =
- requestForName(newTermName(line))
+ private def requestForIdent(line: String): Option[Request] = requestForName(newTermName(line))
+
+ def stringToCompilerType(id: String): compiler.Type = {
+ // if it's a recognized identifier, the type of that; otherwise treat the
+ // String like a value (e.g. scala.collection.Map) .
+ def findType = typeForIdent(id) match {
+ case Some(x) => definitions.getClass(newTermName(x)).tpe
+ case _ => definitions.getModule(newTermName(id)).tpe
+ }
+
+ try findType catch { case _: MissingRequirementError => NoType }
+ }
def typeForIdent(id: String): Option[String] =
- requestForIdent(id) map (_ typeOf newTermName(id))
+ requestForIdent(id) flatMap (x => x.typeOf get newTermName(id))
def methodsOf(name: String) =
evalExpr[List[String]](methodsCode(name)) map (x => NameTransformer.decode(getOriginalName(x)))
@@ -1160,6 +1179,22 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
case x: ImportHandler => x.importedNames
} filterNot isSynthVarName
+ /** Types which have been wildcard imported, such as:
+ * val x = "abc" ; import x._ // type java.lang.String
+ * import java.lang.String._ // object java.lang.String
+ *
+ * Used by tab completion.
+ *
+ * XXX right now this gets import x._ and import java.lang.String._,
+ * but doesn't figure out import String._. There's a lot of ad hoc
+ * scope twiddling which should be swept away in favor of digging
+ * into the compiler scopes.
+ */
+ def wildcardImportedTypes(): List[Type] = {
+ val xs = allHandlers collect { case x: ImportHandler if x.importsWildcard => x.targetType }
+ xs.flatten.reverse.distinct
+ }
+
/** Another entry point for tab-completion, ids in scope */
def unqualifiedIds() = (unqualifiedIdNames() map (_.toString)).distinct.sorted
@@ -1169,16 +1204,6 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
/** Parse the ScalaSig to find type aliases */
def aliasForType(path: String) = ByteCode.aliasForType(path)
- /** Artificial object demonstrating completion */
- def replVarsObject() = CompletionAware(
- Map[String, CompletionAware](
- "ids" -> CompletionAware(() => unqualifiedIds, completionAware _),
- "synthVars" -> CompletionAware(() => allBoundNames filter isSynthVarName map (_.toString)),
- "types" -> CompletionAware(() => allSeenTypes map (_.toString)),
- "implicits" -> CompletionAware(() => allImplicits map (_.toString))
- )
- )
-
// Coming soon
// implicit def string2liftedcode(s: String): LiftedCode = new LiftedCode(s)
// case class LiftedCode(code: String) {
@@ -1191,6 +1216,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
// debugging
def isReplDebug = settings.Yrepldebug.value
+ def isCompletionDebug = settings.Ycompletion.value
def DBG(s: String) = if (isReplDebug) out println s else ()
}
@@ -1275,21 +1301,10 @@ object Interpreter {
* This requires replacing all special characters by escape
* codes. It does not add the surrounding " marks. */
def string2code(str: String): String = {
- /** Convert a character to a backslash-u escape */
- def char2uescape(c: Char): String = {
- var rest = c.toInt
- val buf = new StringBuilder
- for (i <- 1 to 4) {
- buf ++= (rest % 16).toHexString
- rest = rest / 16
- }
- "\\u" + buf.toString.reverse
- }
-
val res = new StringBuilder
for (c <- str) c match {
case '"' | '\'' | '\\' => res += '\\' ; res += c
- case _ if c.isControl => res ++= char2uescape(c)
+ case _ if c.isControl => res ++= Chars.char2uescape(c)
case _ => res += c
}
res.toString
diff --git a/src/compiler/scala/tools/nsc/InterpreterLoop.scala b/src/compiler/scala/tools/nsc/InterpreterLoop.scala
index 9d568418f8..4e8a04de44 100644
--- a/src/compiler/scala/tools/nsc/InterpreterLoop.scala
+++ b/src/compiler/scala/tools/nsc/InterpreterLoop.scala
@@ -211,15 +211,12 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
}
/** Power user commands */
- // XXX - why does a third argument like "interpreter dumpState(_)" throw an NPE
- // while the version below works?
var powerUserOn = false
val powerCommands: List[Command] = {
import CommandImplicits._
List(
- VarArgs("dump", "displays a view of the interpreter's internal state",
- (xs: List[String]) => interpreter dumpState xs),
- OneArg("search", "search the classpath for classes matching regex", search)
+ OneArg("completions", "generate list of completions for a given String", completions),
+ NoArgs("dump", "displays a view of the interpreter's internal state", () => interpreter.power.dump())
// VarArgs("tree", "displays ASTs for specified identifiers",
// (xs: List[String]) => interpreter dumpTrees xs)
@@ -331,45 +328,26 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
else out.println("The path '" + f + "' doesn't seem to exist.")
}
- /** This isn't going to win any efficiency awards, but it's only
- * available in power mode so I'm unconcerned for the moment.
- */
- def search(arg: String) {
- val MAX_RESULTS = 40
- if (in.completion.isEmpty) return println("No classpath data available")
- val comp = in.completion.get
-
- import java.util.regex.PatternSyntaxException
- import comp.pkgs.agent._
- import scala.collection.JavaConversions._
-
- try {
- val regex = arg.r
- val matches = (
- for ((k, vs) <- dottedPaths) yield {
- val pkgs = if (regex findFirstMatchIn k isDefined) List("package " + k) else Nil
- val classes = vs filter (regex findFirstMatchIn _.visibleName isDefined) map (" class " + k + "." + _.visibleName)
-
- pkgs ::: classes
- }
- ).flatten
+ def completions(arg: String): Unit = {
+ val comp = in.completion getOrElse { return println("Completion unavailable.") }
+ val xs = comp completions arg
- matches take MAX_RESULTS foreach println
- }
- catch {
- case _: PatternSyntaxException =>
- return println("Invalid regular expression: you must use java.util.regex.Pattern syntax.")
- }
+ injectAndName(xs)
}
def power() {
- powerUserOn = true
- out println interpreter.powerUser()
- if (in.history.isDefined)
- interpreter.quietBind("history", "scala.collection.immutable.List[String]", in.historyList)
+ val powerUserBanner =
+ """** Power User mode enabled - BEEP BOOP **
+ |** scala.tools.nsc._ has been imported **
+ |** New vals! Try repl, global, power **
+ |** New cmds! :help to discover them **
+ |** New defs! Type power.<tab> to reveal **""".stripMargin
- if (in.completion.isDefined)
- interpreter.quietBind("replHelper", "scala.tools.nsc.interpreter.CompletionAware", interpreter.replVarsObject())
+ powerUserOn = true
+ interpreter.unleash()
+ injectOne("history", in.historyList)
+ in.completion foreach (x => injectOne("completion", x))
+ out println powerUserBanner
}
def verbosity() = {
@@ -496,6 +474,9 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
* to be recorded for replay, if any.
*/
def interpretStartingWith(code: String): Option[String] = {
+ // signal completion non-completion input has been received
+ in.completion foreach (_.resetVerbosity())
+
def reallyInterpret = {
interpreter.interpret(code) match {
case IR.Error => None
@@ -527,7 +508,7 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
interpretAsPastedTranscript(List(code))
None
}
- else if (Completion.looksLikeInvocation(code)) {
+ else if (Completion.looksLikeInvocation(code) && interpreter.mostRecentVar != "") {
interpretStartingWith(interpreter.mostRecentVar + code)
}
else {
diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
index 2e543a0960..430967298c 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
@@ -102,17 +102,20 @@ abstract class TreeInfo {
case _ => false
}
- def isVariableOrGetter(tree: Tree) = tree match {
- case Ident(_) =>
- tree.symbol.isVariable
- case Select(qual, _) =>
- tree.symbol.isVariable ||
- (mayBeVarGetter(tree.symbol) &&
- tree.symbol.owner.info.member(nme.getterToSetter(tree.symbol.name)) != NoSymbol)
- case Apply(Select(qual, nme.apply), _) =>
- qual.tpe.member(nme.update) != NoSymbol
- case _ =>
- false
+ def isVariableOrGetter(tree: Tree) = {
+ def sym = tree.symbol
+ def isVar = sym.isVariable
+ def isGetter = mayBeVarGetter(sym) && sym.owner.info.member(nme.getterToSetter(sym.name)) != NoSymbol
+
+ tree match {
+ case Ident(_) => isVar
+ case Select(_, _) => isVar || isGetter
+ case _ =>
+ methPart(tree) match {
+ case Select(qual, nme.apply) => qual.tpe.member(nme.update) != NoSymbol
+ case _ => false
+ }
+ }
}
/** Is tree a self constructor call?
@@ -295,10 +298,10 @@ abstract class TreeInfo {
/** The method part of an application node
*/
def methPart(tree: Tree): Tree = tree match {
- case Apply(fn, _) => methPart(fn)
- case TypeApply(fn, _) => methPart(fn)
+ case Apply(fn, _) => methPart(fn)
+ case TypeApply(fn, _) => methPart(fn)
case AppliedTypeTree(fn, _) => methPart(fn)
- case _ => tree
+ case _ => tree
}
def firstArgument(tree: Tree): Tree = tree match {
@@ -325,18 +328,19 @@ abstract class TreeInfo {
false
}
- /** Compilation unit is the predef object
+ /** Compilation unit is class or object 'name' in package 'scala'
*/
def isUnitInScala(tree: Tree, name: Name) = tree match {
- case PackageDef(Ident(nme.scala_), defs) => isObject(defs, name)
+ case PackageDef(Ident(nme.scala_), defs) => isImplDef(defs, name)
case _ => false
}
- private def isObject(trees: List[Tree], name: Name): Boolean = trees match {
- case Import(_, _) :: xs => isObject(xs, name)
- case DocDef(_, tree1) :: Nil => isObject(List(tree1), name)
- case Annotated(_, tree1) :: Nil => isObject(List(tree1), name)
+ private def isImplDef(trees: List[Tree], name: Name): Boolean = trees match {
+ case Import(_, _) :: xs => isImplDef(xs, name)
+ case DocDef(_, tree1) :: Nil => isImplDef(List(tree1), name)
+ case Annotated(_, tree1) :: Nil => isImplDef(List(tree1), name)
case ModuleDef(_, `name`, _) :: Nil => true
+ case ClassDef(_, `name`, _, _) :: Nil => true
case _ => false
}
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index 3640b6825b..b40f286680 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -221,9 +221,8 @@ trait Trees extends reflect.generic.Trees { self: SymbolTable =>
var vparamss1 =
vparamss map (vps => vps.map { vd =>
atPos(vd.pos.focus) {
- val pa = if (vd.hasFlag(PRIVATE | LOCAL)) 0L else PARAMACCESSOR
ValDef(
- Modifiers(vd.mods.flags & (IMPLICIT | DEFAULTPARAM | BYNAMEPARAM) | PARAM | pa) withAnnotations vd.mods.annotations,
+ Modifiers(vd.mods.flags & (IMPLICIT | DEFAULTPARAM | BYNAMEPARAM) | PARAM | PARAMACCESSOR) withAnnotations vd.mods.annotations,
vd.name, vd.tpt.duplicate, vd.rhs.duplicate)
}})
val (edefs, rest) = body span treeInfo.isEarlyDef
@@ -260,7 +259,7 @@ trait Trees extends reflect.generic.Trees { self: SymbolTable =>
}
// println("typed template, gvdefs = "+gvdefs+", parents = "+parents+", constrs = "+constrs)
constrs foreach (ensureNonOverlapping(_, parents ::: gvdefs))
- // remove defaults
+ // vparamss2 are used as field definitions for the class. remove defaults
val vparamss2 = vparamss map (vps => vps map { vd =>
treeCopy.ValDef(vd, vd.mods &~ DEFAULTPARAM, vd.name, vd.tpt, EmptyTree)
})
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index 1cfee481bc..497cfc398b 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -2630,7 +2630,8 @@ self =>
} else if (isStatSep) {
in.nextToken()
} else {
- syntaxErrorOrIncomplete("illegal start of statement", true)
+ val addendum = if (isModifier) " (no modifiers allowed here)" else ""
+ syntaxErrorOrIncomplete("illegal start of statement" + addendum, true)
}
}
stats.toList
diff --git a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala
index 87f2641f4f..fb97587ec4 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala
@@ -19,6 +19,8 @@ abstract class SyntaxAnalyzer extends SubComponent with Parsers with MarkupParse
class ParserPhase(prev: scala.tools.nsc.Phase) extends StdPhase(prev) {
override val checkable = false
+ override val keepsTypeParams = false
+
def apply(unit: global.CompilationUnit) {
global.informProgress("parsing " + unit)
unit.body =
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index 5318c76311..dc193b03db 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -851,7 +851,7 @@ abstract class GenJVM extends SubComponent {
def addForwarders(jclass: JClass, module: Symbol) { addForwarders(jclass, module, _ => true) }
def addForwarders(jclass: JClass, module: Symbol, cond: (Symbol) => Boolean) {
def conflictsIn(cls: Symbol, name: Name) =
- cls.info.nonPrivateMembers.exists(_.name == name)
+ cls.info.members exists (_.name == name)
/** List of parents shared by both class and module, so we don't add forwarders
* for methods defined there - bug #1804 */
@@ -874,7 +874,7 @@ abstract class GenJVM extends SubComponent {
atPhase(currentRun.picklerPhase) (
m.owner != definitions.ObjectClass
&& m.isMethod
- && !m.hasFlag(Flags.CASE | Flags.PROTECTED | Flags.DEFERRED | Flags.SPECIALIZED)
+ && !m.hasFlag(Flags.CASE | Flags.PRIVATE | Flags.PROTECTED | Flags.DEFERRED | Flags.SPECIALIZED)
&& !m.isConstructor
&& !m.isStaticMember
&& !(m.owner == definitions.AnyClass)
diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
index 285e09295d..554dcd4e6d 100644
--- a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
+++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
@@ -1053,7 +1053,7 @@ abstract class GenMSIL extends SubComponent {
}
var doEmit = true
- types.get(msym.owner) match {
+ getTypeOpt(msym.owner) match {
case Some(typ) if (typ.IsEnum) => {
def negBool = {
mcode.Emit(OpCodes.Ldc_I4_0)
@@ -1577,9 +1577,9 @@ abstract class GenMSIL extends SubComponent {
mf = mf | FieldAttributes.Static
else {
mf = mf | MethodAttributes.Virtual
- if (sym.isFinal && !types(sym.owner).IsInterface)
+ if (sym.isFinal && !getType(sym.owner).IsInterface)
mf = mf | MethodAttributes.Final
- if (sym.hasFlag(Flags.DEFERRED) || types(sym.owner).IsInterface)
+ if (sym.hasFlag(Flags.DEFERRED) || getType(sym.owner).IsInterface)
mf = mf | MethodAttributes.Abstract
}
}
@@ -1679,8 +1679,14 @@ abstract class GenMSIL extends SubComponent {
sym.tpe.paramTypes.map(msilType).toArray
}
- def getType(sym: Symbol): MsilType = types.get(sym) match {
- case Some(typ) => typ
+ def getType(sym: Symbol) = getTypeOpt(sym).getOrElse(abort(showsym(sym)))
+
+ /**
+ * Get an MSIL type form a symbol. First look in the clrTypes.types map, then
+ * lookup the name using clrTypes.getType
+ */
+ def getTypeOpt(sym: Symbol): Option[MsilType] = types.get(sym) match {
+ case typ @ Some(_) => typ
case None =>
def typeString(sym: Symbol): String = {
val s = if (sym.isNestedClass) typeString(sym.owner) +"+"+ sym.simpleName
@@ -1690,10 +1696,10 @@ abstract class GenMSIL extends SubComponent {
val name = typeString(sym)
val typ = clrTypes.getType(name)
if (typ == null)
- abort(showsym(sym) + " with name " + name)
+ None
else {
- clrTypes.types(sym) = typ
- typ
+ types(sym) = typ
+ Some(typ)
}
}
@@ -1703,10 +1709,20 @@ abstract class GenMSIL extends SubComponent {
}
def createTypeBuilder(iclass: IClass) {
+ /**
+ * First look in the clrTypes.types map, then see if it's a class we're
+ * currently compiling by looking at the icodes.classes map, then finally
+ * lookup the name using clrTypes.getType (by calling getType).
+ */
def msilTypeFromSym(sym: Symbol): MsilType = {
- types.get(sym) match {
- case Some(mtype) => mtype
- case None => createTypeBuilder(classes(sym)); types(sym)
+ types.get(sym).getOrElse {
+ classes.get(sym) match {
+ case Some(iclass) =>
+ createTypeBuilder(iclass)
+ types (sym)
+ case None =>
+ getType(sym)
+ }
}
}
diff --git a/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala b/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala
index 4c7b1977bb..aa784e9c87 100644
--- a/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala
+++ b/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala
@@ -1,6 +1,6 @@
package scala.tools.nsc
-package dependencies;
-import util.SourceFile;
+package dependencies
+import util.SourceFile
import io.AbstractFile
import collection._
import symtab.Flags
@@ -8,11 +8,11 @@ import symtab.Flags
trait DependencyAnalysis extends SubComponent with Files {
import global._
- val phaseName = "dependencyAnalysis";
+ val phaseName = "dependencyAnalysis"
def off = settings.make.value == "all"
- def newPhase(prev : Phase) = new AnalysisPhase(prev)
+ def newPhase(prev: Phase) = new AnalysisPhase(prev)
lazy val maxDepth = settings.make.value match {
case "changed" => 0
@@ -25,7 +25,7 @@ trait DependencyAnalysis extends SubComponent with Files {
// todo: order insensible checking and, also checking timestamp?
def validateClasspath(cp1: String, cp2: String): Boolean = cp1 == cp2
- def nameToFile(src: AbstractFile, name : String) =
+ def nameToFile(src: AbstractFile, name: String) =
settings.outputDirs.outputDirFor(src)
.lookupPathUnchecked(name.toString.replace(".", java.io.File.separator) + ".class", false)
@@ -39,7 +39,7 @@ trait DependencyAnalysis extends SubComponent with Files {
def dependenciesFile: Option[AbstractFile] = depFile
def classpath = settings.classpath.value
- def newDeps = new FileDependencies(classpath);
+ def newDeps = new FileDependencies(classpath)
var dependencies = newDeps
@@ -48,19 +48,19 @@ trait DependencyAnalysis extends SubComponent with Files {
/** Top level definitions per source file. */
val definitions: mutable.Map[AbstractFile, List[Symbol]] =
new mutable.HashMap[AbstractFile, List[Symbol]] {
- override def default(f : AbstractFile) = Nil
+ override def default(f: AbstractFile) = Nil
}
/** External references used by source file. */
val references: mutable.Map[AbstractFile, immutable.Set[String]] =
new mutable.HashMap[AbstractFile, immutable.Set[String]] {
- override def default(f : AbstractFile) = immutable.Set()
+ override def default(f: AbstractFile) = immutable.Set()
}
/** External references for inherited members used in the source file */
val inherited: mutable.Map[AbstractFile, immutable.Set[Inherited]] =
new mutable.HashMap[AbstractFile, immutable.Set[Inherited]] {
- override def default(f : AbstractFile) = immutable.Set()
+ override def default(f: AbstractFile) = immutable.Set()
}
/** Write dependencies to the current file. */
@@ -71,15 +71,14 @@ trait DependencyAnalysis extends SubComponent with Files {
/** Load dependencies from the given file and save the file reference for
* future saves.
*/
- def loadFrom(f: AbstractFile, toFile: String => AbstractFile) : Boolean = {
+ def loadFrom(f: AbstractFile, toFile: String => AbstractFile): Boolean = {
dependenciesFile = f
FileDependencies.readFrom(f, toFile) match {
case Some(fd) =>
val success = if (shouldCheckClasspath) validateClasspath(fd.classpath, classpath) else true
dependencies = if (success) fd else {
- if (settings.debug.value) {
- println("Classpath has changed. Nuking dependencies");
- }
+ if (settings.debug.value)
+ println("Classpath has changed. Nuking dependencies")
newDeps
}
@@ -88,15 +87,13 @@ trait DependencyAnalysis extends SubComponent with Files {
}
}
- def filter(files : List[SourceFile]) : List[SourceFile] =
+ def filter(files: List[SourceFile]): List[SourceFile] =
if (off) files
- else if (dependencies.isEmpty){
- if(settings.debug.value){
- println("No known dependencies. Compiling everything");
- }
+ else if (dependencies.isEmpty) {
+ println("No known dependencies. Compiling " +
+ (if (settings.debug.value) files.mkString(", ") else "everything"))
files
- }
- else {
+ } else {
val (direct, indirect) = dependencies.invalidatedFiles(maxDepth);
val filtered = files.filter(x => {
val f = x.file.absolute
@@ -105,8 +102,7 @@ trait DependencyAnalysis extends SubComponent with Files {
filtered match {
case Nil => println("No changes to recompile");
case x => println("Recompiling " + (
- if(settings.debug.value) x.mkString(", ")
- else x.length + " files")
+ if(settings.debug.value) x.mkString(", ") else x.length + " files")
)
}
filtered
@@ -114,13 +110,13 @@ trait DependencyAnalysis extends SubComponent with Files {
case class Inherited(qualifier: String, member: Name)
- class AnalysisPhase(prev : Phase) extends StdPhase(prev){
+ class AnalysisPhase(prev: Phase) extends StdPhase(prev) {
override def cancelled(unit: CompilationUnit) =
super.cancelled(unit) && !unit.isJava
def apply(unit : global.CompilationUnit) {
- val f = unit.source.file.file;
+ val f = unit.source.file.file
// When we're passed strings by the interpreter
// they have no source file. We simply ignore this case
// as irrelevant to dependency analysis.
@@ -145,7 +141,7 @@ trait DependencyAnalysis extends SubComponent with Files {
dependencies.reset(source)
for (d <- unit.depends; if (d.sourceFile != null)){
- dependencies.depends(source, d.sourceFile);
+ dependencies.depends(source, d.sourceFile)
}
}
diff --git a/src/compiler/scala/tools/nsc/doc/DocFactory.scala b/src/compiler/scala/tools/nsc/doc/DocFactory.scala
index ca72f6581b..7fd6538566 100644
--- a/src/compiler/scala/tools/nsc/doc/DocFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/DocFactory.scala
@@ -52,7 +52,7 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor
compiler.addSourceless
assert(settings.docformat.value == "html")
if (!reporter.hasErrors) {
- val modelFactory = (new model.ModelFactory(compiler, settings))
+ val modelFactory = (new model.ModelFactory(compiler, settings) with model.comment.CommentFactory)
val docModel = modelFactory.makeModel
println("model contains " + modelFactory.templatesCount + " documentable templates")
(new html.HtmlFactory(docModel)) generate docModel
diff --git a/src/compiler/scala/tools/nsc/doc/Settings.scala b/src/compiler/scala/tools/nsc/doc/Settings.scala
index 3d02689605..4897d78488 100644
--- a/src/compiler/scala/tools/nsc/doc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/doc/Settings.scala
@@ -32,4 +32,6 @@ class Settings(error: String => Unit) extends scala.tools.nsc.Settings(error) {
// working around issue described in r18708.
suppressVTWarn.value = true
+
+ // TODO: add a new setting for whether or not to document sourceless entities (e.g., Any, Unit, etc)
}
diff --git a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala
index ae98ecf1f6..31b932ac53 100644
--- a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala
@@ -215,4 +215,10 @@ abstract class HtmlPage { thisPage =>
case tpl :: tpls => templateToHtml(tpl) ++ sep ++ templatesToHtml(tpls, sep)
}
+ def docEntityKindToString(ety: DocTemplateEntity) =
+ if (ety.isTrait) "trait"
+ else if (ety.isClass) "class"
+ else if (ety.isObject) "object"
+ else if (ety.isPackage) "package"
+ else "class" // FIXME: an entity *should* fall into one of the above categories, but AnyRef is somehow not
}
diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Index.scala b/src/compiler/scala/tools/nsc/doc/html/page/Index.scala
index 8f1d537c43..784a92f1ff 100644
--- a/src/compiler/scala/tools/nsc/doc/html/page/Index.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/page/Index.scala
@@ -63,18 +63,41 @@ class Index(universe: Universe) extends HtmlPage {
<ol class="templates">{
val tpls: Map[String, Seq[DocTemplateEntity]] =
(pack.templates filter (t => !t.isPackage && !isExcluded(t) )) groupBy (_.name)
+
+ val placeholderSeq: NodeSeq = <div class="placeholder"></div>
+
+ def createLink(entity: DocTemplateEntity, includePlaceholder: Boolean, includeText: Boolean) = {
+ val entityType = docEntityKindToString(entity)
+ val linkContent = (
+ { if (includePlaceholder) placeholderSeq else NodeSeq.Empty }
+ ++
+ { if (includeText) <span class="tplLink">{ Text(packageQualifiedName(entity)) }</span> else NodeSeq.Empty }
+ )
+ <a class="tplshow" href={ relativeLinkTo(entity) }><span class={ entityType }>({ Text(entityType) })</span>{ linkContent }</a>
+ }
+
for (tn <- tpls.keySet.toSeq sortBy (_.toLowerCase)) yield {
- val entries = tpls(tn) sortWith { (less, more) => less.isTrait || more.isObject }
- def doEntry(ety: DocTemplateEntity, firstEty: Boolean): NodeSeq = {
- val etyTpe =
- if (ety.isTrait) "trait" else if (ety.isClass) "class" else if (ety.isObject) "object" else "package"
- <a class="tplshow" href={ relativeLinkTo(ety) }>
- { if (firstEty) Text(packageQualifiedName(ety)) else NodeSeq.Empty }
- <span class={ etyTpe }>({ Text(etyTpe) })</span>
- </a>
- }
- <li title={ entries.head.qualifiedName }>{
- doEntry(entries.head, true) ++ (entries.tail map (doEntry(_, false)))
+ val entities = tpls(tn)
+ val row = (entities find (e => e.isPackage || e.isObject), entities find (e => e.isTrait || e.isClass))
+
+ val itemContents = row match {
+ case (Some(obj), None) => createLink(obj, includePlaceholder = true, includeText = true)
+
+ case (maybeObj, Some(template)) =>
+ val firstLink = maybeObj match {
+ case Some(obj) => createLink(obj, includePlaceholder = false, includeText = false)
+ case None => placeholderSeq
+ }
+
+ firstLink ++ createLink(template, includePlaceholder = false, includeText = true)
+
+ case _ => // FIXME: this default case should not be necessary. For some reason AnyRef is not a package, object, trait, or class
+ val entry = entities.head
+ placeholderSeq ++ createLink(entry, includePlaceholder = false, includeText = true)
+ }
+
+ <li title={ entities.head.qualifiedName }>{
+ itemContents
}</li>
}
}</ol>
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 41a7de93bd..12d24a7953 100644
--- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala
@@ -60,13 +60,13 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage {
<div id="mbrsel">
{ if (tpl.linearization.isEmpty) NodeSeq.Empty else
<div id="ancestors">
- <h3>Inherited</h3>
+ <span class="filtertype">Inherited</span>
<ol><li class="hideall">Hide All</li><li class="showall">Show all</li></ol>
<ol id="linearization">{ tpl.linearization map { wte => <li class="in" name={ wte.qualifiedName }>{ wte.name }</li> } }</ol>
</div>
}
<div id="visbl">
- <h3>Visibility</h3>
+ <span class="filtertype">Visibility</span>
<ol><li class="public in">Public</li><li class="all out">All</li></ol>
</div>
</div>
@@ -263,8 +263,7 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage {
}
def kindToString(mbr: MemberEntity): String = mbr match {
- case tpl: DocTemplateEntity =>
- if (tpl.isPackage) "package" else if (tpl.isClass) "class" else if (tpl.isTrait) "trait" else "object"
+ case tpl: DocTemplateEntity => docEntityKindToString(tpl)
case ctor: Constructor => "new"
case tme: MemberEntity =>
( if (tme.isImplicit) "implicit " else "" ) +
diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.css b/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.css
index 0bae7dbc3a..fc3f6d4c29 100644
--- a/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.css
+++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.css
@@ -145,10 +145,21 @@ h1 {
}
#tpl ol > li .icon {
+ padding-right: 5px;
bottom: -2px;
position: relative;
}
+#tpl .templates div.placeholder {
+ padding-right: 5px;
+ width: 13px;
+ display: inline-block;
+}
+
+#tpl .templates span.tplLink {
+ padding-left: 8px;
+}
+
#content {
border-left-width: 1px;
border-left-color: black;
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 f315a283b6..92de97f619 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
@@ -198,13 +198,11 @@ div.members > ol > li {
.cmt code {
font-family: monospace;
-/* font-size: small;*/
}
.cmt pre {
display: block;
font-family: monospace;
-/* font-size: small;*/
margin: 2px 0 2px 0;
}
@@ -329,10 +327,12 @@ div.fullcomment dl.paramcmts > dd + dt + dd {
margin-bottom: 10px;
}
-#mbrsel > div > h3 {
+#mbrsel > div > span.filtertype {
padding: 4px;
- display: inline;
+ float: left;
+ display: inline-block;
color: white;
+ width: 4.5em;
}
#mbrsel > div > ol {
@@ -346,7 +346,6 @@ div.fullcomment dl.paramcmts > dd + dt + dd {
#mbrsel > div > ol > li {
padding: 4px 8px 4px 8px;
-/* font-weight: bold;*/
background-color: white;
display: inline-block;
cursor: crosshair;
diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
index d7e1e2fe1a..e2a25d7ea4 100644
--- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
@@ -13,7 +13,7 @@ import symtab.Flags
import model.{ RootPackage => RootPackageEntity }
/** This trait extracts all required information for documentation from compilation units */
-class ModelFactory(val global: Global, val settings: doc.Settings) extends CommentFactory { thisFactory =>
+class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory: ModelFactory with CommentFactory =>
import global._
import definitions.{ ObjectClass, ScalaObjectClass, RootPackage, EmptyPackage, NothingClass, AnyClass, AnyRefClass }
@@ -502,9 +502,11 @@ class ModelFactory(val global: Global, val settings: doc.Settings) extends Comme
val name = optimize(nameBuffer.toString)
}
- def templateShouldDocument(aSym: Symbol): Boolean =
- (aSym.isPackageClass || (aSym.sourceFile != null)) && localShouldDocument(aSym) &&
+ def templateShouldDocument(aSym: Symbol): Boolean = {
+ // TODO: document sourceless entities (e.g., Any, etc), based on a new Setting to be added
+ (aSym.isPackageClass || (aSym.sourceFile != null)) && localShouldDocument(aSym) &&
( aSym.owner == NoSymbol || templateShouldDocument(aSym.owner) )
+ }
def localShouldDocument(aSym: Symbol): Boolean =
!aSym.isPrivate && (aSym.isProtected || aSym.privateWithin == NoSymbol) && !aSym.isSynthetic
diff --git a/src/compiler/scala/tools/nsc/interpreter/ByteCode.scala b/src/compiler/scala/tools/nsc/interpreter/ByteCode.scala
index a998f9dfc8..a42b8347a7 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ByteCode.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ByteCode.scala
@@ -10,7 +10,8 @@ import java.io.File
import java.lang.reflect
import java.util.jar.{ JarEntry, JarFile }
import java.util.concurrent.ConcurrentHashMap
-import util.ScalaClassLoader.getSystemLoader
+import util.ScalaClassLoader
+import ScalaClassLoader.getSystemLoader
object ByteCode {
/** Until I figure out why I can't get scalap onto the classpath such
@@ -34,8 +35,8 @@ object ByteCode {
def scalaSigBytesForPath(path: String) =
for {
module <- DECODER
- method <- decoderMethod("scalaSigBytes", classOf[String], classOf[ClassLoader])
- names <- method.invoke(module, path, this.getClass.getClassLoader).asInstanceOf[Option[Array[Byte]]]
+ method <- decoderMethod("scalaSigAnnotationBytes", classOf[String])
+ names <- method.invoke(module, path).asInstanceOf[Option[Array[Byte]]]
}
yield names
diff --git a/src/compiler/scala/tools/nsc/interpreter/Completion.scala b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
index b90da5bf98..fddb1ee928 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Completion.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
@@ -3,35 +3,14 @@
* @author Paul Phillips
*/
-//
-// TODO, if practical:
-//
-// 1) Types: val s: String = x.<tab> should only show members which result in a String.
-// Possible approach: evaluate buffer as if current identifier is
-// 2) Implicits: x.<tab> should show not only x's members but those of anything for which
-// there is an implicit conversion from x.
-// 4) Imports: after import scala.collection.mutable._, HashMap should be among
-// my top level identifiers.
-// 5) Caching: parsing the jars every startup seems wasteful, but experimentally
-// there is little to no gain from caching.
package scala.tools.nsc
package interpreter
import jline._
-import java.net.URL
import java.util.{ List => JList }
-import java.lang.reflect
-import scala.tools.util.PathResolver
-import io.{ Path, Directory }
object Completion {
- // methods to leave out of completion
- val excludeMethods = List("hashCode", "equals", "wait", "notify", "notifyAll")
-
- // strings to look for an exclude by default
- val excludeStrings = List("$$super", "MODULE$")
-
def looksLikeInvocation(code: String) = (
(code != null)
&& (code startsWith ".")
@@ -40,80 +19,231 @@ object Completion {
&& !(code startsWith "..")
)
- trait Forwarder extends CompletionAware {
- def forwardTo: Option[CompletionAware]
-
- override def completions() = forwardTo map (_.completions()) getOrElse Nil
- override def follow(s: String) = forwardTo flatMap (_ follow s)
+ object Forwarder {
+ def apply(forwardTo: () => Option[CompletionAware]): CompletionAware = new CompletionAware {
+ def completions(verbosity: Int) = forwardTo() map (_ completions verbosity) getOrElse Nil
+ override def follow(s: String) = forwardTo() flatMap (_ follow s)
+ }
}
}
import Completion._
// REPL completor - queries supplied interpreter for valid
// completions based on current contents of buffer.
-class Completion(repl: Interpreter) {
- self =>
+class Completion(val repl: Interpreter) extends CompletionOutput {
+ // verbosity goes up with consecutive tabs
+ private var verbosity: Int = 0
+ def resetVerbosity() = verbosity = 0
- private lazy val classPath = repl.compilerClasspath
+ def isCompletionDebug = repl.isCompletionDebug
+ def DBG(msg: => Any) = if (isCompletionDebug) println(msg.toString)
+ def debugging[T](msg: String): T => T = (res: T) => returning[T](res)(x => DBG(msg + x))
- // the unqualified vals/defs/etc visible in the repl
- val ids = new IdentCompletion(repl)
- // the top level packages we know about
- val pkgs = new PackageCompletion(classPath)
- // members of Predef
- val predef = new StaticCompletion(classOf[scala.Predef$]) {
- override def filterNotFunction(s: String) = (
- (s contains "2") ||
- (s startsWith "wrap") ||
- (s endsWith "Wrapper") ||
- (s endsWith "Ops")
- )
+ lazy val global: repl.compiler.type = repl.compiler
+ import global._
+ import definitions.{ PredefModule, RootClass, AnyClass, AnyRefClass, ScalaPackage, JavaLangPackage }
+
+ // XXX not yet used.
+ lazy val dottedPaths = {
+ def walk(tp: Type): scala.List[Symbol] = {
+ val pkgs = tp.nonPrivateMembers filter (_.isPackage)
+ pkgs ++ (pkgs map (_.tpe) flatMap walk)
+ }
+ walk(RootClass.tpe)
}
- // members of scala.*
- val scalalang = new pkgs.SubCompletor("scala") with Forwarder {
- def forwardTo = pkgs follow "scala"
- val arityClasses = {
- val names = List("Tuple", "Product", "Function")
- val expanded = for (name <- names ; index <- 0 to 22 ; dollar <- List("", "$")) yield name + index + dollar
- Set(expanded: _*)
+ def getType(name: String, isModule: Boolean) = {
+ val f = if (isModule) definitions.getModule(_: Name) else definitions.getClass(_: Name)
+ try Some(f(name).tpe)
+ catch { case _: MissingRequirementError => None }
+ }
+
+ def typeOf(name: String) = getType(name, false)
+ def moduleOf(name: String) = getType(name, true)
+
+ trait CompilerCompletion {
+ def tp: Type
+ def effectiveTp = tp match {
+ case MethodType(Nil, resType) => resType
+ case PolyType(Nil, resType) => resType
+ case _ => tp
}
- override def filterNotFunction(s: String) = {
- val simple = s.reverse takeWhile (_ != '.') reverse
+ // for some reason any's members don't show up in subclasses, which
+ // we need so 5.<tab> offers asInstanceOf etc.
+ private def anyMembers = AnyClass.tpe.nonPrivateMembers
+ def anyRefMethodsToShow = List("isInstanceOf", "asInstanceOf", "toString")
+
+ def tos(sym: Symbol) = sym.name.decode.toString
+ def memberNamed(s: String) = members find (x => tos(x) == s)
+ def hasMethod(s: String) = methods exists (x => tos(x) == s)
+
+ // XXX we'd like to say "filterNot (_.isDeprecated)" but this causes the
+ // compiler to crash for reasons not yet known.
+ def members = (effectiveTp.nonPrivateMembers ++ anyMembers) filter (_.isPublic)
+ def methods = members filter (_.isMethod)
+ def packages = members filter (_.isPackage)
+ def aliases = members filter (_.isAliasType)
- (arityClasses contains simple) ||
- (s endsWith "Exception") ||
- (s endsWith "Error")
+ def memberNames = members map tos
+ def methodNames = methods map tos
+ def packageNames = packages map tos
+ def aliasNames = aliases map tos
+ }
+
+ object TypeMemberCompletion {
+ def apply(tp: Type): TypeMemberCompletion = {
+ if (tp.typeSymbol.isPackageClass) new PackageCompletion(tp)
+ else new TypeMemberCompletion(tp)
}
+ def imported(tp: Type) = new ImportCompletion(tp)
}
- // members of java.lang.*
- val javalang = new pkgs.SubCompletor("java.lang") with Forwarder {
- def forwardTo = pkgs follow "java.lang"
- import reflect.Modifier.isPublic
- private def existsAndPublic(s: String): Boolean = {
- val name = if (s contains ".") s else "java.lang." + s
- val clazz = classForName(name) getOrElse (return false)
-
- isPublic(clazz.getModifiers)
+
+ class TypeMemberCompletion(val tp: Type) extends CompletionAware with CompilerCompletion {
+ def excludeEndsWith: List[String] = Nil
+ def excludeStartsWith: List[String] = List("<") // <byname>, <repeated>, etc.
+ def excludeNames: List[String] = anyref.methodNames -- anyRefMethodsToShow ++ List("_root_")
+
+ def methodSignatureString(sym: Symbol) = {
+ def asString = new MethodSymbolOutput(sym).methodString()
+
+ if (isCompletionDebug)
+ repl.power.showAtAllPhases(asString)
+
+ atPhase(currentRun.typerPhase)(asString)
+ }
+
+ def exclude(name: String): Boolean = (
+ (name contains "$") ||
+ (excludeNames contains name) ||
+ (excludeEndsWith exists (name endsWith _)) ||
+ (excludeStartsWith exists (name startsWith _))
+ )
+ def filtered(xs: List[String]) = xs filterNot exclude distinct
+
+ def completions(verbosity: Int) =
+ debugging(tp + " completions ==> ")(filtered(memberNames))
+
+ override def follow(s: String): Option[CompletionAware] =
+ debugging(tp + " -> '" + s + "' ==> ")(memberNamed(s) map (x => TypeMemberCompletion(x.tpe)))
+
+ override def alternativesFor(id: String): List[String] =
+ debugging(id + " alternatives ==> ") {
+ val alts = members filter (x => x.isMethod && tos(x) == id) map methodSignatureString
+
+ if (alts.nonEmpty) "" :: alts else Nil
+ }
+
+ override def toString = "TypeMemberCompletion(%s)".format(tp)
+ }
+
+ class PackageCompletion(tp: Type) extends TypeMemberCompletion(tp) {
+ override def excludeNames = anyref.methodNames
+ }
+
+ class LiteralCompletion(lit: Literal) extends TypeMemberCompletion(lit.value.tpe) {
+ override def completions(verbosity: Int) = verbosity match {
+ case 0 => filtered(memberNames)
+ case _ => memberNames
+ }
+ }
+
+ class ImportCompletion(tp: Type) extends TypeMemberCompletion(tp) {
+ override def completions(verbosity: Int) = verbosity match {
+ case 0 => filtered(members filterNot (_.isSetter) map tos)
+ case _ => super.completions(verbosity)
+ }
+ }
+
+ // not for completion but for excluding
+ object anyref extends TypeMemberCompletion(AnyRefClass.tpe) { }
+
+ // the unqualified vals/defs/etc visible in the repl
+ object ids extends CompletionAware {
+ override def completions(verbosity: Int) = repl.unqualifiedIds ::: List("classOf")
+ // we try to use the compiler and fall back on reflection if necessary
+ // (which at present is for anything defined in the repl session.)
+ override def follow(id: String) =
+ if (completions(0) contains id) {
+ for (clazz <- repl clazzForIdent id) yield {
+ (typeOf(clazz.getName) map TypeMemberCompletion.apply) getOrElse new InstanceCompletion(clazz)
+ }
+ }
+ else None
+ }
+
+ // wildcard imports in the repl like "import global._" or "import String._"
+ private def imported = repl.wildcardImportedTypes map TypeMemberCompletion.imported
+
+ // literal Ints, Strings, etc.
+ object literals extends CompletionAware {
+ def simpleParse(code: String): Tree = {
+ val unit = new CompilationUnit(new util.BatchSourceFile("<console>", code))
+ val scanner = new syntaxAnalyzer.UnitParser(unit)
+ val tss = scanner.templateStatSeq(false)._2
+
+ if (tss.size == 1) tss.head else EmptyTree
}
- override def filterNotFunction(s: String) = {
- (s endsWith "Exception") ||
- (s endsWith "Error") ||
- (s endsWith "Impl") ||
- (s startsWith "CharacterData")
+
+ def completions(verbosity: Int) = Nil
+
+ override def follow(id: String) = simpleParse(id) match {
+ case x: Literal => Some(new LiteralCompletion(x))
+ case _ => None
}
- override def completions() = super.completions() filter existsAndPublic
}
- val literals = new LiteralCompletion {
- lazy val global = repl.compiler
- val parent = self
+
+ // top level packages
+ object rootClass extends TypeMemberCompletion(RootClass.tpe) { }
+ // members of Predef
+ object predef extends TypeMemberCompletion(PredefModule.tpe) {
+ override def excludeEndsWith = super.excludeEndsWith ++ List("Wrapper", "ArrayOps")
+ override def excludeStartsWith = super.excludeStartsWith ++ List("wrap")
+ override def excludeNames = anyref.methodNames
+
+ override def exclude(name: String) = super.exclude(name) || (
+ (name contains "2")
+ )
+
+ override def completions(verbosity: Int) = verbosity match {
+ case 0 => Nil
+ case _ => super.completions(verbosity)
+ }
}
+ // members of scala.*
+ object scalalang extends PackageCompletion(ScalaPackage.tpe) {
+ def arityClasses = List("Product", "Tuple", "Function")
+ def skipArity(name: String) = arityClasses exists (x => name != x && (name startsWith x))
+ override def exclude(name: String) = super.exclude(name) || (
+ skipArity(name)
+ )
- def lastResult = new Forwarder {
- def forwardTo = ids follow repl.mostRecentVar
+ override def completions(verbosity: Int) = verbosity match {
+ case 0 => filtered(packageNames ++ aliasNames)
+ case _ => super.completions(verbosity)
+ }
+ }
+ // members of java.lang.*
+ object javalang extends PackageCompletion(JavaLangPackage.tpe) {
+ override lazy val excludeEndsWith = super.excludeEndsWith ++ List("Exception", "Error")
+ override lazy val excludeStartsWith = super.excludeStartsWith ++ List("CharacterData")
+
+ override def completions(verbosity: Int) = verbosity match {
+ case 0 => filtered(packageNames)
+ case _ => super.completions(verbosity)
+ }
}
+ // the list of completion aware objects which should be consulted
+ lazy val topLevelBase: List[CompletionAware] = List(ids, rootClass, predef, scalalang, javalang, literals)
+ def topLevel = topLevelBase ++ imported
+
+ // the first tier of top level objects (doesn't include file completion)
+ def topLevelFor(parsed: Parsed) = topLevel flatMap (_ completionsFor parsed)
+
+ // the most recent result
+ def lastResult = Forwarder(() => ids follow repl.mostRecentVar)
+
def lastResultFor(parsed: Parsed) = {
/** The logic is a little tortured right now because normally '.' is
* ignored as a delimiter, but on .<tab> it needs to be propagated.
@@ -122,12 +252,6 @@ class Completion(repl: Interpreter) {
if (parsed.isEmpty) xs map ("." + _) else xs
}
- // the list of completion aware objects which should be consulted
- val topLevel: List[CompletionAware] = List(ids, pkgs, predef, scalalang, javalang, literals)
-
- // the first tier of top level objects (doesn't include file completion)
- def topLevelFor(parsed: Parsed) = topLevel flatMap (_ completionsFor parsed)
-
// chasing down results which won't parse
def execute(line: String): Option[Any] = {
val parsed = Parsed(line)
@@ -136,34 +260,43 @@ class Completion(repl: Interpreter) {
if (noDotOrSlash) None // we defer all unqualified ids to the repl.
else {
(ids executionFor parsed) orElse
- (pkgs executionFor parsed) orElse
+ (rootClass executionFor parsed) orElse
(FileCompletion executionFor line)
}
}
- // override if history is available
- def lastCommand: Option[String] = None
+ // generic interface for querying (e.g. interpreter loop, testing)
+ def completions(buf: String): List[String] =
+ topLevelFor(Parsed.dotted(buf + ".", buf.length + 1))
// jline's entry point
lazy val jline: ArgumentCompletor =
returning(new ArgumentCompletor(new JLineCompletion, new JLineDelimiter))(_ setStrict false)
+ /** This gets a little bit hairy. It's no small feat delegating everything
+ * and also keeping track of exactly where the cursor is and where it's supposed
+ * to end up. The alternatives mechanism is a little hacky: if there is an empty
+ * string in the list of completions, that means we are expanding a unique
+ * completion, so don't update the "last" buffer because it'll be wrong.
+ */
class JLineCompletion extends Completor {
// For recording the buffer on the last tab hit
- private var lastTab: (String, String) = (null, null)
+ private var lastBuf: String = ""
+ private var lastCursor: Int = -1
// Does this represent two consecutive tabs?
- def isConsecutiveTabs(buf: String) = (buf, lastCommand orNull) == lastTab
+ def isConsecutiveTabs(buf: String, cursor: Int) = cursor == lastCursor && buf == lastBuf
- // verbosity goes up with consecutive tabs
- // TODO - actually implement.
- private var verbosity = 0
+ // Longest common prefix
+ def commonPrefix(xs: List[String]) =
+ if (xs.isEmpty) ""
+ else xs.reduceLeft(_ zip _ takeWhile (x => x._1 == x._2) map (_._1) mkString)
// This is jline's entry point for completion.
- override def complete(buf: String, cursor: Int, candidates: JList[String]): Int = {
- // println("complete: buf = %s, cursor = %d".format(buf, cursor))
- verbosity = if (isConsecutiveTabs(buf)) verbosity + 1 else 0
- lastTab = (buf, lastCommand orNull)
+ override def complete(_buf: String, cursor: Int, candidates: JList[String]): Int = {
+ val buf = onull(_buf)
+ verbosity = if (isConsecutiveTabs(buf, cursor)) verbosity + 1 else 0
+ DBG("complete(%s, %d) last = (%s, %d), verbosity: %s".format(buf, cursor, lastBuf, lastCursor, verbosity))
// we don't try lower priority completions unless higher ones return no results.
def tryCompletion(p: Parsed, completionFunction: Parsed => List[String]): Option[Int] = {
@@ -172,17 +305,30 @@ class Completion(repl: Interpreter) {
case xs =>
// modify in place and return the position
xs foreach (candidates add _)
- Some(p.position)
+
+ // update the last buffer unless this is an alternatives list
+ if (xs contains "") Some(p.cursor)
+ else {
+ val advance = commonPrefix(xs)
+ lastCursor = p.position + advance.length
+ lastBuf = (buf take p.position) + advance
+
+ DBG("tryCompletion(%s, _) lastBuf = %s, lastCursor = %s, p.position = %s".format(p, lastBuf, lastCursor, p.position))
+ Some(p.position)
+ }
}
}
+ def mkDotted = Parsed.dotted(buf, cursor) withVerbosity verbosity
+ def mkUndelimited = Parsed.undelimited(buf, cursor) withVerbosity verbosity
+
// a single dot is special cased to completion on the previous result
def lastResultCompletion =
if (!looksLikeInvocation(buf)) None
else tryCompletion(Parsed.dotted(buf drop 1, cursor), lastResultFor)
- def regularCompletion = tryCompletion(Parsed.dotted(buf, cursor), topLevelFor)
- def fileCompletion = tryCompletion(Parsed.undelimited(buf, cursor), FileCompletion completionsFor _.buffer)
+ def regularCompletion = tryCompletion(mkDotted, topLevelFor)
+ def fileCompletion = tryCompletion(mkUndelimited, FileCompletion completionsFor _.buffer)
(lastResultCompletion orElse regularCompletion orElse fileCompletion) getOrElse cursor
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/CompletionAware.scala b/src/compiler/scala/tools/nsc/interpreter/CompletionAware.scala
index 7e94b687bf..cfd3b5e05f 100644
--- a/src/compiler/scala/tools/nsc/interpreter/CompletionAware.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/CompletionAware.scala
@@ -21,8 +21,7 @@ trait CompletionAware {
/** The complete list of unqualified Strings to which this
* object will complete.
*/
- def completions(): List[String]
- def completions(start: String): List[String] = completions filter (_ startsWith start)
+ def completions(verbosity: Int): List[String]
/** Default filter to apply to completions.
*/
@@ -47,6 +46,19 @@ trait CompletionAware {
*/
def execute(id: String): Option[Any] = None
+ /** A list of useful information regarding a specific uniquely
+ * identified completion. This is specifically written for the
+ * following situation, but should be useful elsewhere too:
+ *
+ * x.y.z.methodName<tab>
+ *
+ * If "methodName" is among z's completions, and verbosity > 0
+ * indicating tab has been pressed twice consecutively, then we
+ * call alternativesFor and show a list of overloaded method
+ * signatures.
+ */
+ def alternativesFor(id: String): List[String] = Nil
+
/** Given string 'buf', return a list of all the strings
* to which it can complete. This may involve delegating
* to other CompletionAware objects.
@@ -54,12 +66,16 @@ trait CompletionAware {
def completionsFor(parsed: Parsed): List[String] = {
import parsed._
- val cs =
- if (isEmpty) completions()
- else if (isUnqualified && !isLastDelimiter) completions(buffer)
+ val comps = completions(verbosity) filter (_ startsWith buffer)
+ val results =
+ if (isEmpty) comps
+ else if (isUnqualified && !isLastDelimiter) {
+ if (verbosity > 0 && (comps contains buffer)) alternativesFor(buffer)
+ else comps
+ }
else follow(bufferHead) map (_ completionsFor bufferTail) getOrElse Nil
- cs filterNot filterNotFunction map mapFunction sortWith (sortFunction _)
+ results filterNot filterNotFunction map mapFunction sortWith (sortFunction _)
}
/** TODO - unify this and completionsFor under a common traverser.
@@ -67,14 +83,14 @@ trait CompletionAware {
def executionFor(parsed: Parsed): Option[Any] = {
import parsed._
- if (isUnqualified && !isLastDelimiter && (completions contains buffer)) execute(buffer)
+ if (isUnqualified && !isLastDelimiter && (completions(verbosity) contains buffer)) execute(buffer)
else if (!isQualified) None
else follow(bufferHead) flatMap (_ executionFor bufferTail)
}
}
object CompletionAware {
- val Empty = new CompletionAware { val completions = Nil }
+ val Empty = new CompletionAware { def completions(verbosity: Int) = Nil }
// class Forwarder(underlying: CompletionAware) extends CompletionAware {
// override def completions() = underlying.completions()
@@ -101,6 +117,7 @@ object CompletionAware {
def apply(terms: () => List[String], followFunction: String => Option[CompletionAware]): CompletionAware =
new CompletionAware {
def completions = terms()
+ def completions(verbosity: Int) = completions
override def follow(id: String) = followFunction(id)
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
new file mode 100644
index 0000000000..9b9d9a36f1
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
@@ -0,0 +1,88 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2010 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package interpreter
+
+/** This has a lot of duplication with other methods in Symbols and Types,
+ * but repl completion utility is very sensitive to precise output. Best
+ * thing would be to abstract an interface for how such things are printed,
+ * as is also in progress with error messages.
+ */
+trait CompletionOutput {
+ self: Completion =>
+
+ import global._
+ import definitions.{ NothingClass, AnyClass, isTupleType, isFunctionType, isRepeatedParamType }
+
+ /** Reducing fully qualified noise for some common packages.
+ */
+ val typeTransforms = List(
+ "java.lang." -> "",
+ "scala.collection.immutable." -> "immutable.",
+ "scala.collection.mutable." -> "mutable.",
+ "scala.collection.generic." -> "generic."
+ )
+
+ def quietString(tp: String): String =
+ typeTransforms.foldLeft(tp) {
+ case (str, (prefix, replacement)) =>
+ if (str startsWith prefix) replacement + (str stripPrefix prefix)
+ else str
+ }
+
+ class MethodSymbolOutput(method: Symbol) {
+ val pkg = method.ownerChain find (_.isPackageClass) map (_.fullName) getOrElse ""
+
+ def relativize(str: String): String = quietString(str stripPrefix (pkg + "."))
+ def relativize(tp: Type): String = relativize(tp.normalize.toString)
+ def relativize(sym: Symbol): String = relativize(sym.info)
+
+ def braceList(tparams: List[String]) = if (tparams.isEmpty) "" else (tparams map relativize).mkString("[", ", ", "]")
+ def parenList(params: List[Any]) = params.mkString("(", ", ", ")")
+
+ def methodTypeToString(mt: MethodType) =
+ (mt.paramss map paramsString mkString "") + ": " + relativize(mt.finalResultType)
+
+ def typeToString(tp: Type): String = relativize(
+ tp match {
+ 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
+ }
+ )
+
+ def tupleString(tp: Type) = parenList(tp.normalize.typeArgs map relativize)
+ def functionString(tp: Type) = tp.normalize.typeArgs match {
+ case List(t, r) => t + " => " + r
+ case xs => parenList(xs.init) + " => " + xs.last
+ }
+
+ def tparamsString(tparams: List[Symbol]) = braceList(tparams map (_.defString))
+ def paramsString(params: List[Symbol]) = {
+ def paramNameString(sym: Symbol) = if (sym.isSynthetic) "" else sym.nameString + ": "
+ def paramString(sym: Symbol) = paramNameString(sym) + typeToString(sym.info.normalize)
+
+ val isImplicit = params.nonEmpty && params.head.isImplicit
+ val strs = (params map paramString) match {
+ case x :: xs if isImplicit => ("implicit " + x) :: xs
+ case xs => xs
+ }
+ parenList(strs)
+ }
+
+ def methodString() =
+ method.keyString + " " + method.nameString + (method.info.normalize match {
+ case PolyType(Nil, resType) => ": " + typeToString(resType) // nullary method
+ case PolyType(tparams, resType) => tparamsString(tparams) + typeToString(resType)
+ case mt @ MethodType(_, _) => methodTypeToString(mt)
+ case x =>
+ DBG("methodString(): %s / %s".format(x.getClass, x))
+ x.toString
+ })
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/interpreter/IdentCompletion.scala b/src/compiler/scala/tools/nsc/interpreter/IdentCompletion.scala
deleted file mode 100644
index b0152dbbc6..0000000000
--- a/src/compiler/scala/tools/nsc/interpreter/IdentCompletion.scala
+++ /dev/null
@@ -1,25 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2010 LAMP/EPFL
- * @author Paul Phillips
- */
-
-package scala.tools.nsc
-package interpreter
-
-/** Top level identifiers visible in the repl. It immediately
- * delegates to an InstanceCompletion.
- */
-class IdentCompletion(repl: Interpreter) extends CompletionAware {
- val INTERPRETER_VAR_PREFIX = "res"
-
- def completions() = repl.unqualifiedIds ::: List("classOf")
- override def follow(id: String) =
- // XXX this will be nice but needs solidifying.
- // (repl completionAwareImplicit id) orElse
- if (completions contains id) {
- (repl completionAware id) orElse {
- repl clazzForIdent id map (x => new InstanceCompletion(x))
- }
- }
- else None
-}
diff --git a/src/compiler/scala/tools/nsc/interpreter/LiteralCompletion.scala b/src/compiler/scala/tools/nsc/interpreter/LiteralCompletion.scala
deleted file mode 100644
index 3b74549d27..0000000000
--- a/src/compiler/scala/tools/nsc/interpreter/LiteralCompletion.scala
+++ /dev/null
@@ -1,50 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2010 LAMP/EPFL
- * @author Paul Phillips
- */
-
-package scala.tools.nsc
-package interpreter
-
-import util.BatchSourceFile
-
-/** Literals, so we can pretend they are objects with methods.
- */
-abstract class LiteralCompletion extends CompletionAware {
- val parent: Completion
- val global: Global
-
- import global._
-
- // TODO - figure out how to enumerate available implicit conversions.
- // def richInt = new InstanceCompletion(classOf[scala.runtime.RichInt])
-
- class PrimitiveCompletion(x: Type) extends CompletionAware {
- lazy val completions = x.nonPrivateMembers map (_.name.toString)
- override def follow(s: String) = {
- val member = x.nonPrivateMembers find (_.name.toString == s)
- member flatMap (m => Option(m.tpe)) map (_.resultType) map (x => new PrimitiveCompletion(x))
- }
- }
-
- def simpleParse(code: String): Tree = {
- val unit = new CompilationUnit(new BatchSourceFile("<console>", code))
- val scanner = new syntaxAnalyzer.UnitParser(unit)
-
- // only single statements
- scanner.templateStatSeq(false) match {
- case (_, List(t)) => t
- case (_, x) => EmptyTree
- }
- }
-
- def completions() = Nil
- override def follow(id: String) = simpleParse(id) match {
- case Literal(c @ Constant(_)) => Some(new PrimitiveCompletion(c.tpe))
- // TODO - more AST trees.
- // case Apply(fn @ Ident(name), args) =>
- // classForName(name.toString) map (x => new StaticCompletion(x))
- // None
- case x => None
- }
-}
diff --git a/src/compiler/scala/tools/nsc/interpreter/PackageCompletion.scala b/src/compiler/scala/tools/nsc/interpreter/PackageCompletion.scala
deleted file mode 100644
index 26ae4106c6..0000000000
--- a/src/compiler/scala/tools/nsc/interpreter/PackageCompletion.scala
+++ /dev/null
@@ -1,187 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2010 LAMP/EPFL
- * @author Paul Phillips
- */
-
-package scala.tools.nsc
-package interpreter
-
-import java.net.URL
-import java.lang.reflect
-import java.util.concurrent.ConcurrentHashMap
-import io.{ Path, Directory, File, Streamable }
-import scala.tools.util.PathResolver.Defaults.scalaHomeDir
-import scala.concurrent.DelayedLazyVal
-import scala.reflect.NameTransformer.{ decode, encode }
-import PackageCompletion._
-
-/** Completion among all known packages. It examines the jars in a
- * separate thread so as not to slow down startup. If it arrives at
- * an object, it delegates to StaticCompletion for that object.
- */
-class PackageCompletion(classpath: List[URL]) extends CompletionAware {
- // it takes a little while to look through the jars so we use a future and a concurrent map
- class CompletionAgent {
- val dottedPaths: ConcurrentHashMap[String, List[CompletionInfo]] = new ConcurrentHashMap[String, List[CompletionInfo]]
- val topLevelPackages = new DelayedLazyVal(
- () => enumToList(dottedPaths.keys) filterNot (_ contains '.'),
- getDottedPaths(dottedPaths, classpath)
- )
- }
- val agent = new CompletionAgent
- import agent._
-
- def completions() = topLevelPackages()
- override def follow(id: String) =
- if (dottedPaths containsKey id) Some(new SubCompletor(id))
- else None
-
- class SubCompletor(root: String) extends CompletionAware {
- // Look for a type alias
- private def aliasCompletor(path: String): Option[CompletionAware] =
- for (name <- ByteCode aliasForType path ; clazz <- classForName(name + "$")) yield
- new StaticCompletion(clazz)
-
- lazy val pkgObject = classForName(root + ".package$") map (x => new PackageObjectCompletion(x))
- def pkgObjectMembers = pkgObject map (_ completionsFor Parsed("")) getOrElse Nil
-
- private def infos = Option(dottedPaths get root) getOrElse Nil
- def completions() = {
- val xs = infos map (_.visibleName) filterNot (_ == "package")
- xs ::: pkgObjectMembers
- }
-
- override def follow(segment: String): Option[CompletionAware] = {
- PackageCompletion.this.follow(root + "." + segment) orElse {
- for (CompletionInfo(`segment`, className) <- infos ; clazz <- classForName(className)) {
- return Some(new StaticCompletion(clazz))
- }
-
- aliasCompletor(root + "." + segment)
- }
- }
- override def toString = "SubCompletor(%s)" format root
- }
-}
-
-object PackageCompletion {
- import java.util.jar.{ JarEntry, JarFile }
-
- val EXPAND_SEPARATOR_STRING = "$$"
- val ANON_CLASS_NAME = "$anon"
- val TRAIT_SETTER_SEPARATOR_STRING = "$_setter_$"
- val IMPL_CLASS_SUFFIX ="$class"
-
- def ignoreClassName(x: String) =
- (x contains EXPAND_SEPARATOR_STRING) ||
- (x contains ANON_CLASS_NAME) ||
- (x contains TRAIT_SETTER_SEPARATOR_STRING) ||
- (x endsWith IMPL_CLASS_SUFFIX) ||
- (x matches """.*\$\d+$""")
-
- def enumToList[T](e: java.util.Enumeration[T]): List[T] = enumToListInternal(e, Nil)
- private def enumToListInternal[T](e: java.util.Enumeration[T], xs: List[T]): List[T] =
- if (e == null || !e.hasMoreElements) xs else enumToListInternal(e, e.nextElement :: xs)
-
- private def isClass(s: String) = s endsWith ".class"
- private def processNames(xs: List[String]) = xs map (_ dropRight 6) filterNot ignoreClassName distinct
-
- def getDirClassFiles(dir: Directory): List[String] =
- processNames(dir.deepList() map (dir relativize _ path) filter isClass toList)
-
- def getJarClassFiles(jar: File): List[String] =
- if (!jar.exists) Nil
- else processNames(enumToList(new JarFile(jar.path).entries) map (_.getName) filter isClass)
-
- object CompletionInfo {
- def unapply(that: Any) = that match {
- case x: CompletionInfo => Some((x.visibleName, x.className))
- case _ => None
- }
- }
-
- abstract class CompletionInfo {
- def visibleName: String
- def className: String
- def getBytes(): Array[Byte]
-
- override def hashCode = visibleName.hashCode
- override def equals(other: Any) = other match {
- case x: CompletionInfo => visibleName == x.visibleName
- case _ => false
- }
- }
-
- case class DirCompletionInfo(visibleName: String, className: String, dir: Directory) extends CompletionInfo {
- lazy val file = dir / File(className)
-
- def getBytes(): Array[Byte] = try file.toByteArray() catch { case _: Exception => Array() }
- }
-
- case class JarCompletionInfo(visibleName: String, className: String, jar: File) extends CompletionInfo {
- lazy val jarfile = new JarFile(jar.path)
- lazy val entry = jarfile getEntry className
-
- def getBytes(): Array[Byte] = {
- if (entry == null) Array() else {
- val x = new Streamable.Bytes { def inputStream() = jarfile getInputStream entry }
- x.toByteArray()
- }
- }
- }
-
- // all the dotted path to classfiles we can find by poking through the jars
- def getDottedPaths(map: ConcurrentHashMap[String, List[CompletionInfo]], classpath: List[URL]): Unit = {
- val cp = classpath.distinct map (x => Path(x.getPath))
- val jars = cp filter (_ hasExtension "jar") map (_.toFile)
-
- /** If we process all dirs uncritically, someone who has '.' in their classpath and
- * runs scala from the filesystem root directory will induce a traversal of their
- * entire filesystem. We could apply some heuristics to avoid this, but for now we
- * will look only in the scalaHome directories, which is most of what we want.
- */
- def isUnderScalaHome(d: Directory) = d.parents exists (_ == scalaHomeDir)
- val dirs = cp collect { case x: Directory => x } filter isUnderScalaHome
-
- // for e.g. foo.bar.baz.C, returns (foo -> bar), (foo.bar -> baz), (foo.bar.baz -> C)
- // and scala.Range$BigInt needs to go scala -> Range -> BigInt
- def subpaths(s: String): List[(String, String)] = {
- val segs = decode(s).split("""[/.]""")
- val components = segs dropRight 1
-
- (1 to components.length).toList flatMap { i =>
- val k = components take i mkString "."
- if (segs(i) contains "$") {
- val dollarsegs = segs(i).split("$").toList
- for (j <- 1 to (dollarsegs.length - 1) toList) yield {
- val newk = k + "." + (dollarsegs take j mkString ".")
- (k -> dollarsegs(j))
- }
- }
- else List(k -> segs(i))
- }
- }
-
- def addToMap(key: String, info: CompletionInfo) = {
- if (map containsKey key) {
- val vs = map.get(key)
- if (vs contains info) ()
- else map.put(key, info :: vs)
- }
- else map.put(key, List(info))
- }
-
- def oneDir(dir: Directory) {
- for (cl <- getDirClassFiles(dir) ; (k, v) <- subpaths(cl))
- addToMap(k, DirCompletionInfo(v, cl, dir))
- }
-
- def oneJar(jar: File) {
- for (cl <- getJarClassFiles(jar) ; (k, v) <- subpaths(cl))
- addToMap(k, JarCompletionInfo(v, cl, jar))
- }
-
- jars foreach oneJar
- dirs foreach oneDir
- }
-} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/interpreter/Parsed.scala b/src/compiler/scala/tools/nsc/interpreter/Parsed.scala
index b130396cc6..0b92608d88 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Parsed.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Parsed.scala
@@ -15,18 +15,22 @@ class Parsed private (
val cursor: Int,
val delimited: Char => Boolean
) extends Delimited {
- def isEmpty = buffer == ""
+ def isEmpty = args.isEmpty
def isUnqualified = args.size == 1
def isQualified = args.size > 1
def isAtStart = cursor <= 0
+ private var _verbosity = 0
+ def verbosity = _verbosity
+ def withVerbosity(v: Int): this.type = returning[this.type](this)(_ => _verbosity = v)
+
def args = toArgs(buffer take cursor).toList
def bufferHead = args.head
def headLength = bufferHead.length + 1
- def bufferTail = new Parsed(buffer drop headLength, cursor - headLength, delimited)
+ def bufferTail = new Parsed(buffer drop headLength, cursor - headLength, delimited) withVerbosity verbosity
- def prev = new Parsed(buffer, cursor - 1, delimited)
- def next = new Parsed(buffer, cursor + 1, delimited)
+ def prev = new Parsed(buffer, cursor - 1, delimited) withVerbosity verbosity
+ def next = new Parsed(buffer, cursor + 1, delimited) withVerbosity verbosity
def currentChar = buffer(cursor)
def currentArg = args.last
def position =
@@ -52,7 +56,7 @@ class Parsed private (
object Parsed {
def apply(s: String): Parsed = apply(onull(s), onull(s).length)
- def apply(s: String, cursor: Int): Parsed = apply(onull(s), cursor, "(){},`; \t" contains _)
+ def apply(s: String, cursor: Int): Parsed = apply(onull(s), cursor, "{},`; \t" contains _)
def apply(s: String, cursor: Int, delimited: Char => Boolean): Parsed =
new Parsed(onull(s), cursor, delimited)
diff --git a/src/compiler/scala/tools/nsc/interpreter/ProductCompletion.scala b/src/compiler/scala/tools/nsc/interpreter/ProductCompletion.scala
index 2aaa6114c2..6c066580ae 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ProductCompletion.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ProductCompletion.scala
@@ -8,6 +8,7 @@ package interpreter
class SeqCompletion[T](elems: Seq[T]) extends CompletionAware {
lazy val completions = elems.indices.toList map ("(%d)" format _)
+ def completions(verbosity: Int) = completions
private def elemAt(name: String) =
if (completions contains name) Some(elems(name drop 1 dropRight 1 toInt)) else None
@@ -27,6 +28,7 @@ class ProductCompletion(root: Product) extends CompletionAware {
}
lazy val completions = caseNames
+ def completions(verbosity: Int) = completions
override def execute(name: String) = fieldForName(name)
override def follow(name: String) = fieldForName(name) map (x => ProductCompletion(x))
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/ReflectionCompletion.scala b/src/compiler/scala/tools/nsc/interpreter/ReflectionCompletion.scala
index 89490119ff..f9ff894d59 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ReflectionCompletion.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ReflectionCompletion.scala
@@ -12,7 +12,6 @@ import Modifier.{ isPrivate, isProtected, isStatic }
import scala.reflect.NameTransformer
import scala.collection.mutable.HashMap
import ReflectionCompletion._
-import Completion.{ excludeMethods }
trait ReflectionCompletion extends CompletionAware {
def clazz: Class[_]
@@ -30,12 +29,6 @@ trait ReflectionCompletion extends CompletionAware {
case x => error(x.toString)
}
- override def filterNotFunction(s: String): Boolean = {
- (excludeMethods contains s) ||
- (s contains "$$super") ||
- (s == "MODULE$")
- }
-
lazy val (staticMethods, instanceMethods) = clazz.getMethods.toList partition (x => isStatic(x.getModifiers))
lazy val (staticFields, instanceFields) = clazz.getFields.toList partition (x => isStatic(x.getModifiers))
@@ -53,15 +46,6 @@ trait ReflectionCompletion extends CompletionAware {
}
}
-/** An instance completion which hides a few useless members.
- */
-class PackageObjectCompletion(clazz: Class[_]) extends InstanceCompletion(clazz) {
- override lazy val completions = memberCompletions
- override def filterNotFunction(s: String) = {
- super.filterNotFunction(s) || (s == "getClass") || (s == "toString")
- }
-}
-
/** A completion aware object representing a single instance of some class.
* It completes to instance fields and methods, and delegates to another
* InstanceCompletion object if it can determine the result type of the element.
@@ -70,6 +54,7 @@ class InstanceCompletion(val clazz: Class[_]) extends ReflectionCompletion {
protected def visibleMembers = instanceMethods ::: instanceFields
def extras = List("isInstanceOf", "asInstanceOf", "toString")
lazy val completions = memberCompletions ::: extras
+ def completions(verbosity: Int) = completions
val (zeroArg, otherArg) = instanceMethods partition (_.getParameterTypes.size == 0)
override def follow(id: String) = {
@@ -85,6 +70,7 @@ class InstanceCompletion(val clazz: Class[_]) extends ReflectionCompletion {
class StaticCompletion(val clazz: Class[_]) extends ReflectionCompletion {
protected def visibleMembers = whichMethods ::: whichFields
lazy val completions = memberCompletions
+ def completions(verbosity: Int) = completions
private def aliasForPath(path: String) = ByteCode aliasForType path flatMap (x => classForName(x + "$"))
def className = clazz.getName
diff --git a/src/compiler/scala/tools/nsc/interpreter/XMLCompletion.scala b/src/compiler/scala/tools/nsc/interpreter/XMLCompletion.scala
index 67063192bd..f2af57cc36 100644
--- a/src/compiler/scala/tools/nsc/interpreter/XMLCompletion.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/XMLCompletion.scala
@@ -33,6 +33,7 @@ class XMLCompletion(root: Node) extends CompletionAware {
s :: res
}).sorted
}
+ def completions(verbosity: Int) = completions
override def execute(id: String) = getNode(id)
override def follow(id: String) = getNode(id) map (x => new XMLCompletion(x))
diff --git a/src/compiler/scala/tools/nsc/io/Process.scala b/src/compiler/scala/tools/nsc/io/Process.scala
index 698082d19e..ebd7937f33 100644
--- a/src/compiler/scala/tools/nsc/io/Process.scala
+++ b/src/compiler/scala/tools/nsc/io/Process.scala
@@ -153,9 +153,8 @@ class Process(processCreator: () => JProcess) extends Iterable[String] {
private val reader = new BufferedReader(new InputStreamReader(in))
private def finish() {
- // make sure this thread is complete, and close the process's stdin
+ // make sure this thread is complete
join()
- _in.close()
}
def slurp(): String = {
@@ -171,14 +170,19 @@ class Process(processCreator: () => JProcess) extends Iterable[String] {
def next = it.next
}
}
- @tailrec override final def run() {
- reader.readLine match {
- case null =>
- reader.close()
- case x =>
- queue put x
- run()
+ override final def run() {
+ @tailrec def loop() {
+ reader.readLine match {
+ case null =>
+ reader.close()
+ case x =>
+ queue put x
+ loop()
+ }
}
+
+ try loop()
+ catch { case _: IOException => () }
}
}
diff --git a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala
index ce10f560e9..e35843fc9c 100644
--- a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala
+++ b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala
@@ -29,7 +29,7 @@ abstract class AbstractReporter extends Reporter {
protected def info0(pos: Position, msg: String, _severity: Severity, force: Boolean) {
val severity =
- if (settings.Ywarnfatal.value && _severity == WARNING) ERROR
+ if (settings.Xwarnfatal.value && _severity == WARNING) ERROR
else _severity
severity match {
diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
index b32796e829..e8443d11c1 100644
--- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
@@ -8,7 +8,7 @@ package scala.tools
package nsc
package settings
-import io.AbstractFile
+import io.{AbstractFile, VirtualDirectory}
import scala.tools.util.StringOps
import scala.collection.mutable.ListBuffer
@@ -291,7 +291,11 @@ class MutableSettings(val errorFn: String => Unit) extends AbsSettings with Scal
classFile.path.startsWith(outDir.path)
singleOutDir match {
- case Some(d) => Nil
+ case Some(d) =>
+ d match {
+ case _: VirtualDirectory => Nil
+ case _ => List(d.lookupPathUnchecked(srcPath, false))
+ }
case None =>
(outputs filter (isBelow _).tupled) match {
case Nil => Nil
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 1b6b8297ef..51b47f87d6 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -27,7 +27,6 @@ trait ScalaSettings extends AbsScalaSettings with StandardScalaSettings {
* Temporary Settings
*/
val suppressVTWarn = BooleanSetting ("-Ysuppress-vt-typer-warnings", "Suppress warnings from the typer when testing the virtual class encoding, NOT FOR FINAL!")
- val javaignorecp = BooleanSetting ("-javaignorecp", "Does nothing - is being removed.") // !!! marked for death, but need new starr.
/**
* Standard settings
@@ -80,6 +79,9 @@ trait ScalaSettings extends AbsScalaSettings with StandardScalaSettings {
val Xshowobj = StringSetting ("-Xshow-object", "object", "Show object info", "")
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", "scala.tools.nsc.io.SourceReader")
+ val Xwarnfatal = BooleanSetting ("-Xfatal-warnings", "Fail the compilation if there are any warnings.")
+ val Xwarninit = BooleanSetting ("-Xwarninit", "Warn about possible changes in initialization semantics")
+ val Xchecknull = BooleanSetting ("-Xcheck-null", "Emit warning on selection of nullable reference")
/** Compatibility stubs for options whose value name did
* not previously match the option name.
@@ -133,21 +135,13 @@ trait ScalaSettings extends AbsScalaSettings with StandardScalaSettings {
val Ytyperdebug = BooleanSetting ("-Ytyper-debug", "Trace all type assignements")
val Ypmatdebug = BooleanSetting ("-Ypmat-debug", "Trace all pattern matcher activity.")
val Yrepldebug = BooleanSetting ("-Yrepl-debug", "Trace all repl activity.")
+ val Ycompletion = BooleanSetting ("-Ycompletion-debug", "Trace all tab completion activity.")
val Ypmatnaive = BooleanSetting ("-Ypmat-naive", "Desugar matches as naively as possible..")
- val Ytailrec = BooleanSetting ("-Ytailrecommend", "Alert methods which would be tail-recursive if private or final.")
val Yjenkins = BooleanSetting ("-Yjenkins-hashCodes", "Use jenkins hash algorithm for case class generated hashCodes.")
// Warnings
- val Ywarnfatal = BooleanSetting ("-Yfatal-warnings", "Fail the compilation if there are any warnings.")
- val Xwarninit = BooleanSetting ("-Xwarninit", "Warn about possible changes in initialization semantics")
- val Xchecknull = BooleanSetting ("-Xcheck-null", "Emit warning on selection of nullable reference")
- val Xwarndeadcode = BooleanSetting ("-Ywarn-dead-code", "Emit warnings for dead code")
- val YwarnShadow = BooleanSetting ("-Ywarn-shadowing", "Emit warnings about possible variable shadowing.")
- val YwarnCatches = BooleanSetting ("-Ywarn-catches", "Emit warnings about catch blocks which catch everything.")
- val Xwarnings = BooleanSetting ("-Xstrict-warnings", "Emit warnings about lots of things.") .
- withPostSetHook(_ =>
- List(YwarnShadow, YwarnCatches, Xwarndeadcode, Xwarninit) foreach (_.value = true)
- )
+ val Ywarndeadcode = BooleanSetting ("-Ywarn-dead-code", "Emit warnings for dead code")
+
/**
* "fsc-specific" settings.
*/
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
index a2382063c3..db48189b6b 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -449,7 +449,8 @@ trait Definitions extends reflect.generic.StandardDefinitions {
lazy val BooleanBeanPropertyAttr: Symbol = getClass(sn.BooleanBeanProperty)
lazy val AnnotationDefaultAttr: Symbol = {
- val attr = newClass(RootClass, nme.AnnotationDefaultATTR, List(AnnotationClass.typeConstructor))
+ val RuntimePackageClass = getModule("scala.runtime").tpe.typeSymbol
+ val attr = newClass(RuntimePackageClass, nme.AnnotationDefaultATTR, List(AnnotationClass.typeConstructor))
// This attribute needs a constructor so that modifiers in parsed Java code make sense
attr.info.decls enter (attr newConstructor NoPosition setInfo MethodType(Nil, attr.tpe))
attr
@@ -815,7 +816,7 @@ trait Definitions extends reflect.generic.StandardDefinitions {
StringClass, "+", anyparam, stringtype) setFlag FINAL
val forced = List( // force initialization of every symbol that is entered as a side effect
- AnnotationDefaultAttr,
+ AnnotationDefaultAttr, // #2264
RepeatedParamClass,
JavaRepeatedParamClass,
ByNameParamClass,
@@ -839,9 +840,6 @@ trait Definitions extends reflect.generic.StandardDefinitions {
Object_asInstanceOf
)
- // #2264
- var tmp = AnnotationDefaultAttr
- tmp = RepeatedParamClass // force initialization
if (forMSIL) {
val intType = IntClass.typeConstructor
val intParam = List(intType)
diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
index 5c7e7925ea..9133228768 100644
--- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala
+++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
@@ -95,6 +95,7 @@ trait StdNames extends reflect.generic.StdNames { self: SymbolTable =>
val SELECTOR_DUMMY = newTermName("<unapply-selector>")
val MODULE_INSTANCE_FIELD = newTermName("MODULE$")
+ val SPECIALIZED_INSTANCE = newTermName("specInstance$")
def isLocalName(name: Name) = name.endsWith(LOCAL_SUFFIX)
def isSetterName(name: Name) = name.endsWith(SETTER_SUFFIX)
@@ -122,6 +123,26 @@ trait StdNames extends reflect.generic.StdNames { self: SymbolTable =>
} else name
}
+ /** Return the original name and the types on which this name
+ * is specialized. For example,
+ * {{{
+ * splitSpecializedName("foo$mIcD$sp") == ('foo', "I", "D")
+ * }}}
+ * `foo$mIcD$sp` is the name of a method specialized on two type
+ * parameters, the first one belonging to the method itself, on Int,
+ * and another one belonging to the enclosing class, on Double.
+ */
+ def splitSpecializedName(name: Name): (Name, String, String) =
+ if (name.endsWith("$sp")) {
+ val name1 = name.subName(0, name.length - 3)
+ val idxC = name1.lastPos('c')
+ val idxM = name1.lastPos('m', idxC)
+ (name1.subName(0, idxM - 1).toString,
+ name1.subName(idxC + 1, name1.length).toString,
+ name1.subName(idxM + 1, idxC).toString)
+ } else
+ (name, "", "")
+
def localToGetter(name: Name): Name = {
assert(isLocalName(name))//debug
name.subName(0, name.length - LOCAL_SUFFIX.length)
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index 9c6d6662e3..ebab5d9be7 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -606,6 +606,8 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
supersym == NoSymbol || supersym.isIncompleteIn(base)
}
+ // Does not always work if the rawInfo is a SourcefileLoader, see comment
+ // in "def coreClassesFirst" in Global.
final def exists: Boolean =
this != NoSymbol && (!owner.isPackageClass || { rawInfo.load(this); rawInfo != NoType })
@@ -910,8 +912,11 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
else {
val current = phase
try {
- while (phase.keepsTypeParams && (phase.prev ne NoPhase)) phase = phase.prev
+ while ((phase.prev ne NoPhase) && phase.prev.keepsTypeParams) phase = phase.prev
+// while (phase.keepsTypeParams && (phase.prev ne NoPhase)) phase = phase.prev
if (phase ne current) phase = phase.next
+ if (settings.debug.value && (phase ne current))
+ log("checking unsafeTypeParams(" + this + ") at: " + current + " reading at: " + phase)
rawInfo.typeParams
} finally {
phase = current
@@ -1538,7 +1543,7 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
"package object "+owner.nameString
else
compose(List(kindString,
- if (isClassConstructor) owner.simpleName+idString else nameString))
+ if (isClassConstructor) owner.simpleName.decode+idString else nameString))
/** If owner is a package object, its owner, else the normal owner.
*/
@@ -1742,20 +1747,22 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
private var mtpePeriod = NoPeriod
private var mtpePre: Type = _
private var mtpeResult: Type = _
+ private var mtpeInfo: Type = _
override def cloneSymbolImpl(owner: Symbol): Symbol =
new MethodSymbol(owner, pos, name).copyAttrsFrom(this)
def typeAsMemberOf(pre: Type): Type = {
if (mtpePeriod == currentPeriod) {
- if (mtpePre eq pre) return mtpeResult
+ if ((mtpePre eq pre) && (mtpeInfo eq info)) return mtpeResult
} else if (isValid(mtpePeriod)) {
mtpePeriod = currentPeriod
- if (mtpePre eq pre) return mtpeResult
+ if ((mtpePre eq pre) && (mtpeInfo eq info)) return mtpeResult
}
val res = pre.computeMemberType(this)
mtpePeriod = currentPeriod
mtpePre = pre
+ mtpeInfo = info
mtpeResult = res
res
}
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 863ad7bec4..8f1ece5b9e 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -1205,7 +1205,18 @@ trait Types extends reflect.generic.Types { self: SymbolTable =>
} else {
incCounter(compoundBaseTypeSeqCount)
baseTypeSeqCache = undetBaseTypeSeq
- baseTypeSeqCache = memo(compoundBaseTypeSeq(this))(_.baseTypeSeq updateHead typeSymbol.tpe)
+ baseTypeSeqCache = if (typeSymbol.isRefinementClass)
+ memo(compoundBaseTypeSeq(this))(_.baseTypeSeq updateHead typeSymbol.tpe)
+ else
+ compoundBaseTypeSeq(this)
+ // [Martin] suppressing memo-ization solves the problem with "same type after erasure" errors
+ // when compiling with
+ // scalac scala.collection.IterableViewLike.scala scala.collection.IterableLike.scala
+ // I have not yet figured out precisely why this is the case.
+ // My current assumption is that taking memos forces baseTypeSeqs to be computed
+ // at stale types (i.e. the underlying typeSymbol has already another type).
+ // I do not yet see precisely why this would cause a problem, but it looks
+ // fishy in any case.
}
}
//Console.println("baseTypeSeq(" + typeSymbol + ") = " + baseTypeSeqCache.toList);//DEBUG
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index c78664bc19..fc635874a6 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -876,6 +876,7 @@ abstract class ClassfileParser {
val srcfileLeaf = pool.getName(in.nextChar).toString.trim
val srcpath = sym.enclosingPackage match {
case NoSymbol => srcfileLeaf
+ case definitions.EmptyPackage => srcfileLeaf
case pkg => pkg.fullName(File.separatorChar)+File.separator+srcfileLeaf
}
srcfile0 = settings.outputDirs.srcFilesFor(in.file, srcpath).find(_.exists)
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index 7169516560..ad88b783b4 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -1,4 +1,4 @@
-/* NSC -- new Scala compiler
+/* NSC -- new Scala compiler
* Copyright 2005-2010 LAMP/EPFL
* @author
*/
@@ -25,12 +25,18 @@ abstract class Constructors extends Transform with ast.TreeDSL {
new ConstructorTransformer(unit)
class ConstructorTransformer(unit: CompilationUnit) extends Transformer {
+ import collection.mutable
+
+ private val guardedCtorStats: mutable.Map[Symbol, List[Tree]] = new mutable.HashMap[Symbol, List[Tree]]
def transformClassTemplate(impl: Template): Template = {
val clazz = impl.symbol.owner // the transformed class
val stats = impl.body // the transformed template body
val localTyper = typer.atOwner(impl, clazz)
+ val specializedFlag: Symbol = clazz.info.decl(nme.SPECIALIZED_INSTANCE)
+ val shouldGuard = (specializedFlag != NoSymbol) && !clazz.hasFlag(SPECIALIZED)
+
var constr: DefDef = null // The primary constructor
var constrParams: List[Symbol] = null // ... and its parameters
var constrBody: Block = null // ... and its body
@@ -68,6 +74,7 @@ abstract class Constructors extends Transform with ast.TreeDSL {
}
var thisRefSeen: Boolean = false
+ var usesSpecializedField: Boolean = false
// A transformer for expressions that go into the constructor
val intoConstructorTransformer = new Transformer {
@@ -87,6 +94,8 @@ abstract class Constructors extends Transform with ast.TreeDSL {
gen.mkAttributedIdent(parameter(tree.symbol)) setPos tree.pos
case Select(_, _) =>
thisRefSeen = true
+ if (specializeTypes.specializedTypeVars(tree.symbol).nonEmpty)
+ usesSpecializedField = true
super.transform(tree)
case This(_) =>
thisRefSeen = true
@@ -275,12 +284,106 @@ abstract class Constructors extends Transform with ast.TreeDSL {
copyParam(acc, parameter(acc))
}
+ /** Return a single list of statements, merging the generic class constructor with the
+ * specialized stats. The original statements are retyped in the current class, and
+ * assignments to generic fields that have a corresponding specialized assignment in
+ * `specializedStats` are replaced by the specialized assignment.
+ */
+ def mergeConstructors(genericClazz: Symbol, originalStats: List[Tree], specializedStats: List[Tree]): List[Tree] = {
+ val specBuf = new ListBuffer[Tree]
+ specBuf ++= specializedStats
+
+ def specializedAssignFor(sym: Symbol): Option[Tree] =
+ specializedStats.find {
+ case Assign(sel @ Select(This(_), _), rhs) if sel.symbol.hasFlag(SPECIALIZED) =>
+ val (generic, _, _) = nme.splitSpecializedName(nme.localToGetter(sel.symbol.name))
+ generic == nme.localToGetter(sym.name)
+ case _ => false
+ }
+
+ log("merging: " + originalStats.mkString("\n") + " : " + specializedStats.mkString("\n"))
+ val res = for (s <- originalStats; val stat = s.duplicate) yield {
+ log("merge: looking at " + stat)
+ val stat1 = stat match {
+ case Assign(sel @ Select(This(_), field), _) =>
+ specializedAssignFor(sel.symbol).getOrElse(stat)
+ case _ => stat
+ }
+ if (stat1 ne stat) {
+ log("replaced " + stat + " with " + stat1)
+ specBuf -= stat1
+ }
+
+ if (stat1 eq stat) {
+ // statements coming from the original class need retyping in the current context
+ if (settings.debug.value) log("retyping " + stat1)
+ val d = new specializeTypes.Duplicator
+ d.retyped(localTyper.context1.asInstanceOf[d.Context],
+ stat1,
+ genericClazz,
+ clazz,
+ Map.empty)
+ } else
+ stat1
+ }
+ if (specBuf.nonEmpty)
+ println("residual specialized constructor statements: " + specBuf)
+ res
+ }
+
+ /** Add an 'if' around the statements coming after the super constructor. This
+ * guard is necessary if the code uses specialized fields. A specialized field is
+ * initialized in the subclass constructor, but the accessors are (already) overridden
+ * and pointing to the (empty) fields. To fix this, a class with specialized fields
+ * will not run its constructor statements if the instance is specialized. The specialized
+ * subclass includes a copy of those constructor statements, and runs them. To flag that a class
+ * has specialized fields, and their initialization should be deferred to the subclass, method
+ * 'specInstance$' is added in phase specialize.
+ */
+ def guardSpecializedInitializer(stats0: List[Tree]): List[Tree] = if (settings.nospecialization.value) stats0 else {
+ // split the statements in presuper and postsuper
+ var (prefix, postfix) = stats0.span(tree => !((tree.symbol ne null) && tree.symbol.isConstructor))
+ if (postfix.nonEmpty) {
+ prefix = prefix :+ postfix.head
+ postfix = postfix.tail
+ }
+
+ if (usesSpecializedField && shouldGuard && postfix.nonEmpty) {
+ // save them for duplication in the specialized subclass
+ guardedCtorStats(clazz) = postfix
+
+ val tree =
+ If(
+ Apply(
+ Select(
+ Apply(gen.mkAttributedRef(specializedFlag), List()),
+ definitions.getMember(definitions.BooleanClass, nme.UNARY_!)),
+ List()),
+ Block(postfix, Literal(())),
+ EmptyTree)
+
+ prefix ::: List(localTyper.typed(tree))
+ } else if (clazz.hasFlag(SPECIALIZED)) {
+ // add initialization from its generic class constructor
+ val (genericName, _, _) = nme.splitSpecializedName(clazz.name)
+ val genericClazz = clazz.owner.info.decl(genericName.toTypeName)
+ assert(genericClazz != NoSymbol)
+
+ guardedCtorStats.get(genericClazz) match {
+ case Some(stats1) =>
+ val merged = mergeConstructors(genericClazz, stats1, postfix)
+ prefix ::: merged
+ case None => stats0
+ }
+ } else stats0
+ }
+
// Assemble final constructor
defBuf += treeCopy.DefDef(
constr, constr.mods, constr.name, constr.tparams, constr.vparamss, constr.tpt,
treeCopy.Block(
constrBody,
- paramInits ::: constrPrefixBuf.toList ::: constrStatBuf.toList,
+ paramInits ::: constrPrefixBuf.toList ::: guardSpecializedInitializer(constrStatBuf.toList),
constrBody.expr));
// Unlink all fields that can be dropped from class scope
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 94d52bc1cb..88a7e13d80 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -152,7 +152,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.
if (unboundedGenericArrayLevel(tp) == 1) ObjectClass.tpe
else if (args.head.typeSymbol == NothingClass || args.head.typeSymbol == NullClass) arrayType(ObjectClass.tpe)
else typeRef(apply(pre), sym, args map this)
- else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass) erasedTypeRef(ObjectClass)
+ else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass || sym == NotNullClass) erasedTypeRef(ObjectClass)
else if (sym == UnitClass) erasedTypeRef(BoxedUnitClass)
else if (sym.isRefinementClass) apply(intersectionDominator(tp.parents))
else if (sym.isClass) typeRef(apply(rebindInnerClass(pre, sym)), sym, List()) // #2585
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index d5d7ca254e..1ab310282d 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -119,6 +119,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
* type bounds of other @specialized type parameters (and not in its result type).
*/
def degenerate = false
+
+ def isAccessor = false
}
/** Symbol is a special overloaded method of 'original', in the environment env. */
@@ -132,11 +134,16 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
}
/** Symbol is a specialized accessor for the `target' field. */
- case class SpecializedAccessor(target: Symbol) extends SpecializedInfo
+ case class SpecializedAccessor(target: Symbol) extends SpecializedInfo {
+ override def isAccessor = true
+ }
/** Symbol is a specialized method whose body should be the target's method body. */
case class Implementation(target: Symbol) extends SpecializedInfo
+ /** Symbol is a specialized override paired with `target'. */
+ case class SpecialOverride(target: Symbol) extends SpecializedInfo
+
/** An Inner class that specializes on a type parameter of the enclosing class. */
case class SpecializedInnerClass(target: Symbol, env: TypeEnv) extends SpecializedInfo
@@ -217,18 +224,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
* specialization on method type parameters, the second on outer environment.
*/
private def specializedName(name: Name, types1: List[Type], types2: List[Type]): Name = {
- def split: (String, String, String) = {
- if (name.endsWith("$sp")) {
- val name1 = name.subName(0, name.length - 3)
- val idxC = name1.lastPos('c')
- val idxM = name1.lastPos('m', idxC)
- (name1.subName(0, idxM - 1).toString,
- name1.subName(idxC + 1, name1.length).toString,
- name1.subName(idxM + 1, idxC).toString)
- } else
- (name.toString, "", "")
- }
-
if (nme.INITIALIZER == name || (types1.isEmpty && types2.isEmpty))
name
else if (nme.isSetterName(name))
@@ -236,8 +231,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
else if (nme.isLocalName(name))
nme.getterToLocal(specializedName(nme.localToGetter(name), types1, types2))
else {
- val (base, cs, ms) = split
- newTermName(base + "$"
+ val (base, cs, ms) = nme.splitSpecializedName(name)
+ newTermName(base.toString + "$"
+ "m" + ms + types1.map(t => definitions.abbrvTag(t.typeSymbol)).mkString("", "", "")
+ "c" + cs + types2.map(t => definitions.abbrvTag(t.typeSymbol)).mkString("", "", "$sp"))
}
@@ -319,21 +314,20 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
}))
- private def specializedTypeVars(tpe: List[Type]): immutable.Set[Symbol] =
+ def specializedTypeVars(tpe: List[Type]): immutable.Set[Symbol] =
tpe.foldLeft(immutable.ListSet.empty[Symbol]: immutable.Set[Symbol]) {
(s, tp) => s ++ specializedTypeVars(tp)
}
- private def specializedTypeVars(sym: Symbol): immutable.Set[Symbol] =
+ def specializedTypeVars(sym: Symbol): immutable.Set[Symbol] =
specializedTypeVars(atPhase(currentRun.typerPhase)(sym.info))
/** Return the set of @specialized type variables mentioned by the given type. */
- private def specializedTypeVars(tpe: Type): immutable.Set[Symbol] = tpe match {
+ def specializedTypeVars(tpe: Type): immutable.Set[Symbol] = tpe match {
case TypeRef(pre, sym, args) =>
if (sym.isTypeParameter && sym.hasAnnotation(SpecializedClass))
specializedTypeVars(args) + sym
else if (sym.isTypeSkolem && sym.deSkolemize.hasAnnotation(SpecializedClass)) {
- println("cought skolem without @specialized")
specializedTypeVars(args) + sym
} else
specializedTypeVars(args)
@@ -680,48 +674,51 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
*/
private def specialOverrides(clazz: Symbol): List[Symbol] = {
log("specialOverrides(" + clazz + ")")
- val opc = new overridingPairs.Cursor(clazz)
val oms = new mutable.ListBuffer[Symbol]
- while (opc.hasNext) {
+ for (overriding <- clazz.info.decls;
+ val allOverridden = overriding.allOverriddenSymbols
+ if !allOverridden.isEmpty;
+ val overridden = allOverridden.head) {
if (settings.debug.value)
- log("\toverriding pairs: " + opc.overridden.fullName + ": " + opc.overridden.info
- + " overriden by " + opc.overriding.fullName + ": " + opc.overriding.info)
- if (opc.overriding.owner == clazz && !specializedTypeVars(opc.overridden.info).isEmpty) {
- if (settings.debug.value) log("\t\tspecializedTVars: " + specializedTypeVars(opc.overridden.info))
- val env = unify(opc.overridden.info, opc.overriding.info, emptyEnv)
+ log("\toverriding pairs: " + overridden.fullName + ": " + overridden.info
+ + " overriden by " + overriding.fullName + ": " + overriding.info)
+ if (overriding.owner == clazz && !specializedTypeVars(overridden.info).isEmpty) {
+ if (settings.debug.value) log("\t\tspecializedTVars: " + specializedTypeVars(overridden.info))
+ val env = unify(overridden.info, overriding.info, emptyEnv)
if (settings.debug.value)
log("\t\tenv: " + env + "isValid: "
- + TypeEnv.isValid(env, opc.overridden)
- + " exists: " + opc.overridden.owner.info.decl(specializedName(opc.overridden, env)))
+ + TypeEnv.isValid(env, overridden)
+ + " looking for: " + specializedName(overridden, env) + " in:\n"
+ + atPhase(phase.next)(overridden.owner.info.decls)
+ + "found: " + atPhase(phase.next)(overridden.owner.info.decl(specializedName(overridden, env))))
if (!env.isEmpty
- && TypeEnv.isValid(env, opc.overridden)
- && opc.overridden.owner.info.decl(specializedName(opc.overridden, env)) != NoSymbol) {
- log("Added specialized overload for " + opc.overriding.fullName + " in env: " + env)
- val om = specializedOverload(clazz, opc.overridden, env)
+ && TypeEnv.isValid(env, overridden)
+ && atPhase(phase.next)(overridden.owner.info.decl(specializedName(overridden, env))) != NoSymbol) {
+ log("Added specialized overload for " + overriding.fullName + " in env: " + env)
+ val om = specializedOverload(clazz, overridden, env)
typeEnv(om) = env
- if (!opc.overriding.isDeferred) {
- concreteSpecMethods += opc.overriding
+ if (!overriding.isDeferred) {
+ concreteSpecMethods += overriding
// if the override is a normalized member, 'om' gets the implementation from
// its original target, and adds the environment of the normalized member (that is,
// any specialized /method/ type parameter bindings)
- info(om) = info.get(opc.overriding) match {
+ info(om) = info.get(overriding) match {
case Some(NormalizedMember(target)) =>
- typeEnv(om) = env ++ typeEnv(opc.overriding)
- Implementation(target)
- case _ => Implementation(opc.overriding)
+ typeEnv(om) = env ++ typeEnv(overriding)
+ SpecialOverride(target)
+ case _ => SpecialOverride(overriding)
}
- info(opc.overriding) = Forward(om)
+ info(overriding) = Forward(om)
log("typeEnv(om) = " + typeEnv(om))
- om setPos opc.overriding.pos // set the position of the concrete, overriding member
+ om setPos overriding.pos // set the position of the concrete, overriding member
}
- overloads(opc.overriding) = Overload(om, env) :: overloads(opc.overriding)
+ overloads(overriding) = Overload(om, env) :: overloads(overriding)
oms += om
atPhase(phase.next)(
- assert(opc.overridden.owner.info.decl(om.name) != NoSymbol,
- "Could not find " + om.name + " in " + opc.overridden.owner.info.decls))
+ assert(overridden.owner.info.decl(om.name) != NoSymbol,
+ "Could not find " + om.name + " in " + overridden.owner.info.decls))
}
}
- opc.next
}
oms.toList
}
@@ -827,13 +824,19 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
case PolyType(targs, ClassInfoType(base, decls, clazz)) =>
val parents = base map specializedType
log("transformInfo (poly) " + clazz + " with parents1: " + parents + " ph: " + phase)
- PolyType(targs, ClassInfoType(parents, new Scope(specializeClass(clazz, typeEnv(clazz))), clazz))
+// if (clazz.name.toString == "$colon$colon")
+// (new Throwable).printStackTrace
+ PolyType(targs, ClassInfoType(parents,
+ new Scope(specializeClass(clazz, typeEnv(clazz)) ::: specialOverrides(clazz)),
+ clazz))
case ClassInfoType(base, decls, clazz) if !clazz.isPackageClass =>
atPhase(phase.next)(base.map(_.typeSymbol.info))
val parents = base map specializedType
log("transformInfo " + clazz + " with parents1: " + parents + " ph: " + phase)
- val res = ClassInfoType(base map specializedType, new Scope(specializeClass(clazz, typeEnv(clazz))), clazz)
+ val res = ClassInfoType(base map specializedType,
+ new Scope(specializeClass(clazz, typeEnv(clazz)) ::: specialOverrides(clazz)),
+ clazz)
res
case _ =>
@@ -893,16 +896,12 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
satisfiable(env, silent)
}
- import java.io.PrintWriter
-
/*************************** Term transformation ************************************/
class Duplicator extends {
val global: SpecializeTypes.this.global.type = SpecializeTypes.this.global
} with typechecker.Duplicators
- import global.typer.typed
-
def specializeCalls(unit: CompilationUnit) = new TypingTransformer(unit) {
/** Map a specializable method to it's rhs, when not deferred. */
val body: mutable.Map[Symbol, Tree] = new mutable.HashMap
@@ -928,8 +927,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
}
}
- import posAssigner._
-
override def transform(tree: Tree): Tree = {
val symbol = tree.symbol
@@ -1036,7 +1033,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
case (tpe, idx) => TypeTree(tpe) setPos parents(idx).pos
}
treeCopy.Template(tree,
- parents1 /*currentOwner.info.parents.map(tpe => TypeTree(tpe) setPos parents.head.pos)*/,
+ parents1 /*currentOwner.info.parents.map(tpe => TypeTree(tpe) setPos parents.head.pos)*/ ,
self,
atOwner(currentOwner)(transformTrees(body ::: specMembers)))
@@ -1091,6 +1088,18 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
treeCopy.DefDef(tree1, mods, name, tparams, vparamss, tpt, transform(rhs))
}
+ case SpecialOverride(target) =>
+ assert(body.isDefinedAt(target), "sym: " + symbol.fullName + " target: " + target.fullName)
+ if (settings.debug.value) log("moving implementation: " + body(target))
+ // we have an rhs, specialize it
+ val tree1 = addBody(ddef, target)
+ (new ChangeOwnerTraverser(target, tree1.symbol))(tree1.rhs)
+ if (settings.debug.value)
+ println("changed owners, now: " + tree1)
+ val DefDef(mods, name, tparams, vparamss, tpt, rhs) = tree1
+ treeCopy.DefDef(tree1, mods, name, tparams, vparamss, tpt, transform(rhs))
+
+
case SpecialOverload(original, env) =>
log("completing specialized " + symbol.fullName + " calling " + original)
val t = DefDef(symbol, { vparamss =>
@@ -1118,7 +1127,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
localTyper.typed(treeCopy.DefDef(tree, mods, name, tparams, vparamss, tpt, rhs1))
}
- case ValDef(mods, name, tpt, rhs) if symbol.hasFlag(SPECIALIZED) =>
+ case ValDef(mods, name, tpt, rhs) if symbol.hasFlag(SPECIALIZED) && !symbol.hasFlag(PARAMACCESSOR) =>
assert(body.isDefinedAt(symbol.alias))
val tree1 = treeCopy.ValDef(tree, mods, name, tpt, body(symbol.alias).duplicate)
if (settings.debug.value) log("now typing: " + tree1 + " in " + tree.symbol.owner.fullName)
@@ -1128,8 +1137,20 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
symbol.alias.enclClass,
symbol.enclClass,
typeEnv(symbol.alias) ++ typeEnv(tree.symbol))
+// val tree1 =
+// treeCopy.ValDef(tree, mods, name, tpt,
+// localTyper.typed(
+// Apply(Select(Super(currentClass, nme.EMPTY), symbol.alias.getter(symbol.alias.owner)),
+// List())))
+// if (settings.debug.value) log("replaced ValDef: " + tree1 + " in " + tree.symbol.owner.fullName)
+// tree1
+
+ case Apply(sel @ Select(sup @ Super(qual, name), name1), args)
+ if (sup.symbol.info.parents != atPhase(phase.prev)(sup.symbol.info.parents)) =>
+
+ def parents = sup.symbol.info.parents
+ log(tree + " parents changed from: " + atPhase(phase.prev)(parents) + " to: " + parents)
- case Apply(sel @ Select(sup @ Super(qual, name), name1), args) =>
val res = localTyper.typed(
Apply(Select(Super(qual, name) setPos sup.pos, name1) setPos sel.pos, transformTrees(args)) setPos tree.pos)
log("retyping call to super, from: " + symbol + " to " + res.symbol)
@@ -1146,11 +1167,31 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
(tparams1, tparams map (_.symbol))
}
- private def duplicateBody(tree: DefDef, target: Symbol): Tree = {
+
+ private def duplicateBody(tree: DefDef, source: Symbol) = {
+ val symbol = tree.symbol
+ val meth = addBody(tree, source)
+ log("now typing: " + meth + " in " + symbol.owner.fullName)
+ val d = new Duplicator
+ d.retyped(localTyper.context1.asInstanceOf[d.Context],
+ meth,
+ source.enclClass,
+ symbol.enclClass,
+ typeEnv(source) ++ typeEnv(symbol))
+ }
+
+
+ /** Put the body of 'source' as the right hand side of the method 'tree'.
+ * The destination method gets fresh symbols for type and value parameters,
+ * and the body is updated to the new symbols, and owners adjusted accordingly.
+ * However, if the same source tree is used in more than one place, full re-typing
+ * is necessary. @see method duplicateBody
+ */
+ private def addBody(tree: DefDef, source: Symbol): DefDef = {
val symbol = tree.symbol
if (settings.debug.value) log("specializing body of" + symbol.fullName + ": " + symbol.info)
val DefDef(mods, name, tparams, vparamss, tpt, _) = tree
- val (_, origtparams) = splitParams(target.typeParams)
+ val (_, origtparams) = splitParams(source.typeParams)
if (settings.debug.value) log("substituting " + origtparams + " for " + symbol.typeParams)
// skolemize type parameters
@@ -1163,21 +1204,12 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
// replace value and type parameters of the old method with the new ones
val symSubstituter = new ImplementationAdapter(
- parameters(target).flatten ::: origtparams,
+ parameters(source).flatten ::: origtparams,
vparamss1.flatten.map(_.symbol) ::: newtparams)
- val adapter = new AdaptSpecializedValues
- val tmp = symSubstituter(adapter(body(target).duplicate))
+ val tmp = symSubstituter(body(source).duplicate)
tpt.tpe = tpt.tpe.substSym(oldtparams, newtparams)
- val meth = treeCopy.DefDef(tree, mods, name, tparams, vparamss1, tpt, tmp)
-
- log("now typing: " + meth + " in " + symbol.owner.fullName)
- val d = new Duplicator
- d.retyped(localTyper.context1.asInstanceOf[d.Context],
- meth,
- target.enclClass,
- symbol.enclClass,
- typeEnv(target) ++ typeEnv(symbol))
+ treeCopy.DefDef(tree, mods, name, tparams, vparamss1, tpt, tmp)
}
/** A tree symbol substituter that substitutes on type skolems.
@@ -1201,10 +1233,12 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
*/
override def transform(tree: Tree): Tree = tree match {
case Select(qual, name) =>
- if (tree.symbol.hasFlag(PRIVATE | PROTECTED)) {
- log("changing private flag of " + tree.symbol + " privateWithin: " + tree.symbol.privateWithin)
+ val sym = tree.symbol
+ if (sym.hasFlag(PRIVATE | PROTECTED) && !nme.isLocalName(sym.name)
+ && (currentClass != sym.owner.enclClass)) {
+ log("changing private flag of " + sym)
// tree.symbol.resetFlag(PRIVATE).setFlag(PROTECTED)
- tree.symbol.makeNotPrivate(tree.symbol.owner)
+ sym.makeNotPrivate(sym.owner)
// tree.symbol.resetFlag(PRIVATE | PROTECTED)
// tree.symbol.privateWithin = NoSymbol
}
@@ -1215,36 +1249,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
}
}
- /** Does the given tree need a cast to a type parameter's upper bound?
- * A cast is needed for values of type A, where A is a specialized type
- * variable with a non-trivial upper bound. When A is specialized, its
- * specialization may not satisfy the upper bound. We generate casts to
- * be able to type check code. Such methods will never be called, as they
- * are not visible to the user. The compiler will insert such calls only when
- * the bounds are satisfied.
- */
- private class AdaptSpecializedValues extends Transformer {
- private def needsCast(tree: Tree): Boolean = {
- val sym = tree.tpe.typeSymbol
- (sym.isTypeParameterOrSkolem
- && sym.hasAnnotation(SpecializedClass)
- && sym.info.bounds.hi != definitions.AnyClass.tpe
- /*&& !(tree.tpe <:< sym.info.bounds.hi)*/)
- }
-
- override def transform(tree: Tree): Tree = {
- val tree1 = super.transform(tree)
- if (needsCast(tree1)) {
-// log("inserting cast for " + tree1 + " tpe: " + tree1.tpe)
-// val tree2 = gen.mkAsInstanceOf(tree1, tree1.tpe.typeSymbol.info.bounds.hi)
-// log(" casted to: " + tree2)
- tree1
- } else
- tree1
- }
- def apply(t: Tree): Tree = transform(t)
- }
-
def warn(clazz: Symbol)(pos: Position, err: String) =
if (!clazz.hasFlag(SPECIALIZED))
unit.warning(pos, err)
@@ -1254,9 +1258,10 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
*/
private def makeSpecializedMembers(cls: Symbol): List[Tree] = {
// add special overrides first
- if (!cls.hasFlag(SPECIALIZED))
- for (m <- specialOverrides(cls)) cls.info.decls.enter(m)
+// if (!cls.hasFlag(SPECIALIZED))
+// for (m <- specialOverrides(cls)) cls.info.decls.enter(m)
val mbrs = new mutable.ListBuffer[Tree]
+ var hasSpecializedFields = false
for (m <- cls.info.decls.toList
if m.hasFlag(SPECIALIZED)
@@ -1264,6 +1269,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
&& satisfiable(typeEnv(m), warn(cls))) {
log("creating tree for " + m.fullName)
if (m.isMethod) {
+ if (info(m).target.isGetterOrSetter) hasSpecializedFields = true
if (m.isClassConstructor) {
val origParamss = parameters(info(m).target)
assert(origParamss.length == 1) // we are after uncurry
@@ -1294,6 +1300,14 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
// log("created synthetic class: " + m.fullName)
}
}
+ if (hasSpecializedFields) {
+ val sym = cls.newMethod(nme.SPECIALIZED_INSTANCE, cls.pos)
+ .setInfo(MethodType(Nil, definitions.BooleanClass.tpe))
+ cls.info.decls.enter(sym)
+ mbrs += atPos(sym.pos) {
+ DefDef(sym, Literal(cls.hasFlag(SPECIALIZED)).setType(sym.tpe.finalResultType)).setType(NoType)
+ }
+ }
mbrs.toList
}
@@ -1372,6 +1386,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
}
class SpecializationTransformer(unit: CompilationUnit) extends Transformer {
+ log("specializing " + unit)
override def transform(tree: Tree) =
atPhase(phase.next) {
val res = specializeCalls(unit).transform(tree)
diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
index adeab550ee..9fff8534d3 100644
--- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala
+++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
@@ -39,9 +39,6 @@ abstract class TailCalls extends Transform
}
}
- /** The @tailrec annotation indicates TCO is mandatory */
- private def tailrecRequired(defdef: DefDef) = defdef.symbol hasAnnotation TailrecClass
-
/**
* A Tail Call Transformer
*
@@ -105,6 +102,9 @@ abstract class TailCalls extends Transform
/** Tells whether we are in a (possible) tail position */
var tailPos = false
+ /** The reason this method could not be optimized. */
+ var tailrecFailReason = "it contains a recursive call not in tail position"
+
/** Is the label accessed? */
var accessed = false
@@ -138,7 +138,8 @@ abstract class TailCalls extends Transform
t
}
- private var ctx: Context = new Context()
+ private var ctx: Context = new Context()
+ private def enclosingType = ctx.currentMethod.enclClass.typeOfThis
/** Rewrite this tree to contain no tail recursive calls */
def transform(tree: Tree, nctx: Context): Tree = {
@@ -150,11 +151,50 @@ abstract class TailCalls extends Transform
}
override def transform(tree: Tree): Tree = {
+ /** A possibly polymorphic apply to be considered for tail call transformation.
+ */
+ def rewriteApply(target: Tree, fun: Tree, targs: List[Tree], args: List[Tree]) = {
+ def isRecursiveCall = ctx.currentMethod eq fun.symbol
+ def isMandatory = ctx.currentMethod hasAnnotation TailrecClass
+ def isEligible = ctx.currentMethod.isEffectivelyFinal
+ def transformArgs = transformTrees(args, mkContext(ctx, false))
+ def matchesTypeArgs = ctx.tparams sameElements (targs map (_.tpe.typeSymbol))
+ def defaultTree = treeCopy.Apply(tree, target, transformArgs)
+
+ def sameTypeOfThis(receiver: Tree) =
+ receiver.tpe.widen =:= enclosingType.widen
+
+ /** Records failure reason in Context for reporting.
+ */
+ def cannotRewrite(reason: String) = {
+ if (isMandatory)
+ ctx.tailrecFailReason = reason
+
+ defaultTree
+ }
+ def rewriteTailCall(receiver: Tree, otherArgs: List[Tree]): Tree = {
+ log("Rewriting tail recursive method call at: " + fun.pos)
+
+ ctx.accessed = true
+ typed { atPos(fun.pos)(Apply(Ident(ctx.label), receiver :: otherArgs)) }
+ }
+
+ if (!isRecursiveCall) defaultTree
+ else if (!isEligible) cannotRewrite("it is neither private nor final so can be overridden")
+ else if (!ctx.tailPos) cannotRewrite("it contains a recursive call not in tail position")
+ else if (!matchesTypeArgs) cannotRewrite("it is called recursively with different type arguments")
+ else fun match {
+ case Select(_, _) if forMSIL => cannotRewrite("it cannot be optimized on MSIL")
+ case Select(qual, _) if !sameTypeOfThis(qual) => cannotRewrite("it changes type of 'this' on a polymorphic recursive call")
+ case Select(qual, _) => rewriteTailCall(qual, transformArgs)
+ case _ => rewriteTailCall(This(currentClass), transformArgs)
+ }
+ }
+
tree match {
case dd @ DefDef(mods, name, tparams, vparams, tpt, rhs) =>
log("Entering DefDef: " + name)
- var isTransformed = false
val newCtx = mkContext(ctx)
newCtx.currentMethod = tree.symbol
newCtx.makeLabel()
@@ -162,16 +202,10 @@ abstract class TailCalls extends Transform
newCtx.label.setInfo(MethodType(currentClassParam :: tree.symbol.tpe.params, tree.symbol.tpe.finalResultType))
newCtx.tailPos = true
- val isEligible = newCtx.currentMethod.isEffectivelyFinal || (newCtx.currentMethod.enclClass hasFlag Flags.MODULE)
- // If -Ytailrecommend is given, we speculatively try transforming ineligible methods and
- // report where we would have been successful.
- val recommend = settings.Ytailrec.value
- val savedFlags: Option[Long] = if (recommend) Some(newCtx.currentMethod.flags) else None
-
- if (isEligible || recommend) {
- if (recommend)
- newCtx.currentMethod.flags |= Flags.FINAL
+ val isEligible = newCtx.currentMethod.isEffectivelyFinal
+ val isMandatory = dd.symbol.hasAnnotation(TailrecClass) && !forMSIL // @tailrec annotation indicates mandatory transformation
+ if (isEligible) {
newCtx.tparams = Nil
log(" Considering " + name + " for tailcalls")
tree.symbol.tpe match {
@@ -185,12 +219,10 @@ abstract class TailCalls extends Transform
val t1 = treeCopy.DefDef(tree, mods, name, tparams, vparams, tpt, {
val transformed = transform(rhs, newCtx)
- savedFlags foreach (newCtx.currentMethod.flags = _)
transformed match {
case newRHS if isEligible && newCtx.accessed =>
log("Rewrote def " + newCtx.currentMethod)
- isTransformed = true
val newThis = newCtx.currentMethod
. newValue (tree.pos, nme.THIS)
. setInfo (currentClass.typeOfThis)
@@ -200,19 +232,14 @@ abstract class TailCalls extends Transform
List(ValDef(newThis, This(currentClass))),
LabelDef(newCtx.label, newThis :: (vparams.flatten map (_.symbol)), newRHS)
)))
- case _ if recommend =>
- if (newCtx.accessed)
- unit.warning(dd.pos, "method is tailrecommended")
- // transform with the original flags restored
- transform(rhs, newCtx)
+ case rhs =>
+ if (isMandatory)
+ unit.error(dd.pos, "could not optimize @tailrec annotated method: " + newCtx.tailrecFailReason)
- case rhs => rhs
+ rhs
}
})
- if (!forMSIL && !isTransformed && tailrecRequired(dd))
- unit.error(dd.pos, "could not optimize @tailrec annotated method")
-
log("Leaving DefDef: " + name)
t1
@@ -269,50 +296,16 @@ abstract class TailCalls extends Transform
case Typed(expr, tpt) => super.transform(tree)
case Apply(tapply @ TypeApply(fun, targs), vargs) =>
- lazy val defaultTree = treeCopy.Apply(tree, tapply, transformTrees(vargs, mkContext(ctx, false)))
- if ( ctx.currentMethod.isEffectivelyFinal &&
- ctx.tailPos &&
- isSameTypes(ctx.tparams, targs map (_.tpe.typeSymbol)) &&
- isRecursiveCall(fun)) {
- fun match {
- case Select(receiver, _) =>
- val recTpe = receiver.tpe.widen
- val enclTpe = ctx.currentMethod.enclClass.typeOfThis
- // make sure the type of 'this' doesn't change through this polymorphic recursive call
- if (!forMSIL &&
- (receiver.tpe.typeParams.isEmpty ||
- (receiver.tpe.widen == ctx.currentMethod.enclClass.typeOfThis)))
- rewriteTailCall(fun, receiver :: transformTrees(vargs, mkContext(ctx, false)))
- else
- defaultTree
- case _ => rewriteTailCall(fun, This(currentClass) :: transformTrees(vargs, mkContext(ctx, false)))
- }
- } else
- defaultTree
+ rewriteApply(tapply, fun, targs, vargs)
case TypeApply(fun, args) =>
super.transform(tree)
- case Apply(fun, args) if (fun.symbol == definitions.Boolean_or ||
- fun.symbol == definitions.Boolean_and) =>
- treeCopy.Apply(tree, fun, transformTrees(args))
-
case Apply(fun, args) =>
- lazy val defaultTree = treeCopy.Apply(tree, fun, transformTrees(args, mkContext(ctx, false)))
- if (ctx.currentMethod.isEffectivelyFinal &&
- ctx.tailPos &&
- isRecursiveCall(fun)) {
- fun match {
- case Select(receiver, _) =>
- if (!forMSIL)
- rewriteTailCall(fun, receiver :: transformTrees(args, mkContext(ctx, false)))
- else
- defaultTree
- case _ => rewriteTailCall(fun, This(currentClass) :: transformTrees(args, mkContext(ctx, false)))
- }
- } else
- defaultTree
-
+ if (fun.symbol == Boolean_or || fun.symbol == Boolean_and)
+ treeCopy.Apply(tree, fun, transformTrees(args))
+ else
+ rewriteApply(fun, fun, Nil, args)
case Super(qual, mix) =>
tree
@@ -333,28 +326,5 @@ abstract class TailCalls extends Transform
def transformTrees(trees: List[Tree], nctx: Context): List[Tree] =
trees map ((tree) => transform(tree, nctx))
-
- private def rewriteTailCall(fun: Tree, args: List[Tree]): Tree = {
- log("Rewriting tail recursive method call at: " +
- (fun.pos))
- ctx.accessed = true
- //println("fun: " + fun + " args: " + args)
- val t = atPos(fun.pos)(Apply(Ident(ctx.label), args))
- // println("TAIL: "+t)
- typed(t)
- }
-
- private def isSameTypes(ts1: List[Symbol], ts2: List[Symbol]) = ts1 sameElements ts2
-
- /** Returns <code>true</code> if the fun tree refers to the same method as
- * the one saved in <code>ctx</code>.
- *
- * @param fun the expression that is applied
- * @return <code>true</code> if the tree symbol refers to the innermost
- * enclosing method
- */
- private def isRecursiveCall(fun: Tree): Boolean =
- (fun.symbol eq ctx.currentMethod)
}
-
}
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index e339560837..bad98193b0 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -659,11 +659,6 @@ abstract class UnCurry extends InfoTransform with TypingTransformers {
}
treeCopy.DefDef(tree, mods, name, tparams, List(vparamss.flatten), tpt, rhs1)
case Try(body, catches, finalizer) =>
- // If warnings are enabled, alert about promiscuously catching cases.
- if (settings.YwarnCatches.value)
- for (cd <- catches find treeInfo.catchesThrowable)
- unit.warning(cd.pos, "catch clause swallows everything: not advised.")
-
if (catches forall treeInfo.isCatchCase) tree
else {
val exname = unit.fresh.newName(tree.pos, "ex$")
diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
index 635608520d..70bf55e661 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
@@ -22,6 +22,7 @@ trait Analyzer extends AnyRef
with SyntheticMethods
with Unapplies
with NamesDefaults
+ with TypeDiagnostics
{
val global : Global
import global._
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index becb4b069f..8758dd834c 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -256,23 +256,25 @@ trait Contexts { self: Analyzer =>
if (diagnostic.isEmpty) ""
else diagnostic.mkString("\n","\n", "")
- def error(pos: Position, err: Throwable) {
- val msg = err.getMessage() + diagString
- if (reportGeneralErrors)
- unit.error(pos, if (checking) "**** ERROR DURING INTERNAL CHECKING ****\n" + msg else msg)
- else
- throw err
+ private def addDiagString(msg: String) = {
+ val ds = diagString
+ if (msg endsWith ds) msg else msg + ds
}
- def error(pos: Position, msg: String) {
- val msg1 = msg + diagString
- if (reportGeneralErrors)
- unit.error(pos, if (checking) "**** ERROR DURING INTERNAL CHECKING ****\n" + msg1 else msg1)
- else
- throw new TypeError(pos, msg1)
+ private def unitError(pos: Position, msg: String) =
+ unit.error(pos, if (checking) "**** ERROR DURING INTERNAL CHECKING ****\n" + msg else msg)
+
+ def error(pos: Position, err: Throwable) =
+ if (reportGeneralErrors) unitError(pos, addDiagString(err.getMessage()))
+ else throw err
+
+ def error(pos: Position, msg: String) = {
+ val msg1 = addDiagString(msg)
+ if (reportGeneralErrors) unitError(pos, msg1)
+ else throw new TypeError(pos, msg1)
}
- def warning(pos: Position, msg: String) {
+ def warning(pos: Position, msg: String) = {
if (reportGeneralErrors) unit.warning(pos, msg)
}
@@ -484,6 +486,19 @@ trait Contexts { self: Analyzer =>
}
implicitsCache
}
+
+ def lookup(name: Name, expectedOwner: Symbol) = {
+ var res: Symbol = NoSymbol
+ var ctx = this
+ while(res == NoSymbol && ctx.outer != ctx) {
+ val s = ctx.scope.lookup(name)
+ if (s != NoSymbol && s.owner == expectedOwner)
+ res = s
+ else
+ ctx = ctx.outer
+ }
+ res
+ }
}
class ImportInfo(val tree: Import, val depth: Int) {
/** The prefix expression */
diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala
index 1dbeb0afd9..de9318d6b6 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala
@@ -94,6 +94,15 @@ abstract class Duplicators extends Analyzer {
} else
super.mapOver(tpe)
+ case ThisType(sym) =>
+ val sym1 = updateSym(sym)
+ if (sym1 ne sym) {
+ log("fixing " + sym + " -> " + sym1)
+ ThisType(sym1)
+ } else
+ super.mapOver(tpe)
+
+
case _ =>
super.mapOver(tpe)
}
@@ -136,7 +145,7 @@ abstract class Duplicators extends Analyzer {
ldef.symbol = newsym
log("newsym: " + newsym + " info: " + newsym.info)
- case DefDef(_, _, tparams, vparamss, _, rhs) =>
+ case DefDef(_, name, tparams, vparamss, _, rhs) =>
// invalidate parameters
invalidate(tparams ::: vparamss.flatten)
tree.symbol = NoSymbol
@@ -244,6 +253,11 @@ abstract class Duplicators extends Analyzer {
if (settings.debug.value) log("mapped " + tree + " to " + tree1)
super.typed(atPos(tree.pos)(tree1), mode, pt)
+ case This(_) =>
+ tree.symbol = updateSym(tree.symbol)
+ tree.tpe = null
+ super.typed(tree, mode, pt)
+
case Super(qual, mix) if (oldClassOwner ne null) && (tree.symbol == oldClassOwner) =>
val tree1 = Super(qual, mix)
log("changed " + tree + " to " + tree1)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 4c07e50da9..9a6c4cc401 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -639,9 +639,9 @@ self: Analyzer =>
val applicable = applicableInfos(implicitInfoss, isLocal, invalidImplicits)
if (applicable.isEmpty && !invalidImplicits.isEmpty) {
- infer.setAddendum(tree.pos, () =>
+ setAddendum(tree.pos, () =>
"\n Note: implicit "+invalidImplicits.head+" is not applicable here"+
- "\n because it comes after the application point and it lacks an explicit result type")
+ " because it comes after the application point and it lacks an explicit result type")
}
val start = startCounter(subtypeImprovCount)
@@ -784,7 +784,6 @@ self: Analyzer =>
inferImplicit(tree, appliedType(manifestClass.typeConstructor, List(tp)), true, false, context).tree
def findSubManifest(tp: Type) = findManifest(tp, if (full) FullManifestClass else OptManifestClass)
- def findElemManifest(tp: Type) = findManifest(tp, if (full) FullManifestClass else PartialManifestClass)
def mot(tp0: Type): Tree = {
val tp1 = tp0.normalize
@@ -801,39 +800,26 @@ self: Analyzer =>
} else if (sym == RepeatedParamClass || sym == ByNameParamClass) {
EmptyTree
} else if (sym == ArrayClass && args.length == 1) {
- manifestFactoryCall("arrayType", args.head, findElemManifest(args.head))
+ manifestFactoryCall("arrayType", args.head, findManifest(args.head))
} else if (sym.isClass) {
- val suffix = gen.mkClassOf(tp1) :: (args map findSubManifest)
+ val classarg0 = gen.mkClassOf(tp1)
+ val classarg = tp match {
+ case ExistentialType(_, _) =>
+ TypeApply(Select(classarg0, Any_asInstanceOf),
+ List(TypeTree(appliedType(ClassClass.typeConstructor, List(tp)))))
+ case _ =>
+ classarg0
+ }
+ val suffix = classarg :: (args map findSubManifest)
manifestFactoryCall(
"classType", tp,
(if ((pre eq NoPrefix) || pre.typeSymbol.isStaticOwner) suffix
else findSubManifest(pre) :: suffix): _*)
- } else {
- EmptyTree
-/* the following is dropped because it is dangerous
- *
- if (sym.isAbstractType) {
- if (sym.isExistentiallyBound)
- EmptyTree // todo: change to existential parameter manifest
- else if (sym.isTypeParameterOrSkolem)
- EmptyTree // a manifest should have been found by normal searchImplicit
- else {
- // The following is tricky! We want to find the parameterized version of
- // what will become the erasure of the upper bound.
- // But there is a case where the erasure is not a superclass of the current type:
- // Any erases to Object. So an abstract type having Any as upper bound will not see
- // Object as a baseType. That's why we do the basetype trick only when we must,
- // i.e. when the baseclass is parameterized.
- var era = erasure.erasure(tp1)
- if (era.typeSymbol.typeParams.nonEmpty)
- era = tp1.baseType(era.typeSymbol)
- manifestFactoryCall(
- "abstractType", tp,
- findSubManifest(pre) :: Literal(sym.name.toString) :: gen.mkClassOf(era) :: (args map findSubManifest): _*)
- }
+ } else if (sym.isExistentiallyBound && full) {
+ manifestFactoryCall("wildcardType", tp,
+ findManifest(tp.bounds.lo), findManifest(tp.bounds.hi))
} else {
EmptyTree // a manifest should have been found by normal searchImplicit
-*/
}
case RefinedType(parents, decls) =>
// refinement is not generated yet
@@ -841,10 +827,7 @@ self: Analyzer =>
else if (full) manifestFactoryCall("intersectionType", tp, parents map (findSubManifest(_)): _*)
else mot(erasure.erasure.intersectionDominator(parents))
case ExistentialType(tparams, result) =>
- existentialAbstraction(tparams, result) match {
- case ExistentialType(_, _) => mot(result)
- case t => mot(t)
- }
+ mot(tp1.skolemizeExistential)
case _ =>
EmptyTree
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index c8d3308077..1ee1604319 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -120,7 +120,7 @@ trait Infer {
case NoPrefix | ThisType(_) | ConstantType(_) =>
true
case TypeRef(pre, sym, args) =>
- isFullyDefined(pre) && (args.isEmpty || (args forall isFullyDefined))
+ isFullyDefined(pre) && (args forall isFullyDefined)
case SingleType(pre, sym) =>
isFullyDefined(pre)
case RefinedType(ts, decls) =>
@@ -197,72 +197,17 @@ trait Infer {
/** The context-dependent inferencer part */
class Inferencer(context: Context) {
-
/* -- Error Messages --------------------------------------------------- */
-
- private var addendumPos: Position = NoPosition
- private var addendum: () => String = _
-
- def setAddendum(pos: Position, msg: () => String) = {
- addendumPos = pos
- addendum = msg
- }
-
def setError[T <: Tree](tree: T): T = {
- if (tree.hasSymbol)
- if (context.reportGeneralErrors) {
- val name = newTermName("<error: " + tree.symbol + ">")
- tree.setSymbol(
- if (tree.isType) context.owner.newErrorClass(name.toTypeName)
- else context.owner.newErrorValue(name))
- } else {
- tree.setSymbol(if (tree.isType) stdErrorClass else stdErrorValue)
- }
- tree.setType(ErrorType)
- }
-
- def decode(name: Name): String =
- (if (name.isTypeName) "type " else "value ") + name.decode
+ def name = newTermName("<error: " + tree.symbol + ">")
+ def errorClass = if (context.reportGeneralErrors) context.owner.newErrorClass(name.toTypeName) else stdErrorClass
+ def errorValue = if (context.reportGeneralErrors) context.owner.newErrorValue(name) else stdErrorValue
+ def errorSym = if (tree.isType) errorClass else errorValue
- def treeSymTypeMsg(tree: Tree): String =
- if (tree.symbol eq null)
- "expression of type " + tree.tpe
- else if (tree.symbol.hasFlag(OVERLOADED))
- "overloaded method " + tree.symbol + " with alternatives " + tree.tpe
- else
- tree.symbol.toString() +
- (if (tree.symbol.isModule) ""
- else if (tree.tpe.paramSectionCount > 0) ": "+tree.tpe
- else " of type "+tree.tpe) +
- (if (tree.symbol.name == nme.apply) tree.symbol.locationString else "")
-
- def applyErrorMsg(tree: Tree, msg: String, argtpes: List[Type], pt: Type) =
- treeSymTypeMsg(tree) + msg + argtpes.mkString("(", ",", ")") +
- (if (isWildcard(pt)) "" else " with expected result type " + pt)
-
- // todo: use also for other error messages
- private def existentialContext(tp: Type) = tp.existentialSkolems match {
- case List() => ""
- case skolems =>
- def disambiguate(ss: List[String]) = ss match {
- case List() => ss
- case s :: ss1 => s :: (ss1 map (s1 => if (s1 == s) "(some other)"+s1 else s1))
- }
- " where "+(disambiguate(skolems map (_.existentialToString)) mkString ", ")
- }
-
- def foundReqMsg(found: Type, req: Type): String =
- withDisambiguation(found, req) {
- ";\n found : " + found.toLongString + existentialContext(found) +
- "\n required: " + req + existentialContext(req)
- }
+ if (tree.hasSymbol)
+ tree setSymbol errorSym
- def typeErrorMsg(found: Type, req: Type) = {
- //println(found.baseTypeSeq)
- "type mismatch" + foundReqMsg(found, req) +
- (if ((found.resultApprox ne found) && isWeaklyCompatible(found.resultApprox, req))
- "\n possible cause: missing arguments for method or constructor"
- else "")
+ tree setType ErrorType
}
def error(pos: Position, msg: String) {
@@ -276,67 +221,27 @@ trait Infer {
def typeError(pos: Position, found: Type, req: Type) {
if (!found.isErroneous && !req.isErroneous) {
- error(pos,
- typeErrorMsg(found, req)+
- (if (pos != NoPosition && pos == addendumPos) addendum()
- else ""))
- if (settings.explaintypes.value) explainTypes(found, req)
+ error(pos, withAddendum(pos)(typeErrorMsg(found, req)))
+
+ if (settings.explaintypes.value)
+ explainTypes(found, req)
}
}
+ def typeErrorMsg(found: Type, req: Type) = {
+ def isPossiblyMissingArgs = (found.resultApprox ne found) && isWeaklyCompatible(found.resultApprox, req)
+ def missingArgsMsg = if (isPossiblyMissingArgs) "\n possible cause: missing arguments for method or constructor" else ""
+
+ "type mismatch" + foundReqMsg(found, req) + missingArgsMsg
+ }
+
def typeErrorTree(tree: Tree, found: Type, req: Type): Tree = {
typeError(tree.pos, found, req)
setError(tree)
}
def explainTypes(tp1: Type, tp2: Type) =
- withDisambiguation(tp1, tp2) { global.explainTypes(tp1, tp2) }
-
- /** If types `tp1' `tp2' contain different type variables with same name
- * differentiate the names by including owner information. Also, if the
- * type error is because of a conflict between two identically named
- * classes and one is in package scala, fully qualify the name so one
- * need not deduce why "java.util.Iterator" and "Iterator" don't match.
- */
- private def withDisambiguation[T](tp1: Type, tp2: Type)(op: => T): T = {
-
- def explainName(sym: Symbol) = {
- if (!sym.name.toString.endsWith(")")) {
- sym.name = newTypeName(sym.name.toString+"(in "+sym.owner+")")
- }
- }
-
- val patches = new ListBuffer[(Symbol, Symbol, Name)]
- for {
- t1 @ TypeRef(_, sym1, _) <- tp1
- t2 @ TypeRef(_, sym2, _) <- tp2
- if sym1 != sym2
- } {
- if (t1.toString == t2.toString) { // type variable collisions
- val name = sym1.name
- explainName(sym1)
- explainName(sym2)
- if (sym1.owner == sym2.owner) sym2.name = newTypeName("(some other)"+sym2.name)
- patches += ((sym1, sym2, name))
- }
- else if (sym1.name == sym2.name) { // symbol name collisions where one is in scala._
- val name = sym1.name
- def scalaQualify(s: Symbol) =
- if (s.owner.isScalaPackageClass) s.name = newTypeName("scala." + s.name)
- List(sym1, sym2) foreach scalaQualify
- patches += ((sym1, sym2, name))
- }
- }
-
- val result = op
-
- for ((sym1, sym2, name) <- patches) {
- sym1.name = name
- sym2.name = name
- }
-
- result
- }
+ withDisambiguation(tp1, tp2)(global.explainTypes(tp1, tp2))
/* -- Tests & Checks---------------------------------------------------- */
@@ -1591,7 +1496,7 @@ trait Infer {
}
def checkDead(tree: Tree): Tree = {
- if (settings.Xwarndeadcode.value && tree.tpe != null && tree.tpe.typeSymbol == NothingClass)
+ if (settings.Ywarndeadcode.value && tree.tpe != null && tree.tpe.typeSymbol == NothingClass)
context.warning (tree.pos, "dead code following this construct")
tree
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index a78ee61ee2..a7f573f98b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -607,6 +607,17 @@ trait Namers { self: Analyzer =>
vparamss.map(_.map(enterValueParam))
}
+ /**
+ * Finds the companion module of a class symbol. Calling .companionModule
+ * does not work for classes defined inside methods.
+ */
+ private def companionModuleOf(clazz: Symbol) = {
+ var res = clazz.companionModule
+ if (res == NoSymbol)
+ res = context.lookup(clazz.name.toTermName, clazz.owner)
+ res
+ }
+
private def templateSig(templ: Template): Type = {
val clazz = context.owner
def checkParent(tpt: Tree): Type = {
@@ -712,29 +723,36 @@ trait Namers { self: Analyzer =>
// add apply and unapply methods to companion objects of case classes,
// unless they exist already; here, "clazz" is the module class
- Namers.this.caseClassOfModuleClass get clazz match {
- case Some(cdef) =>
- addApplyUnapply(cdef, templateNamer)
- caseClassOfModuleClass -= clazz
- case None =>
+ if (clazz.isModuleClass) {
+ Namers.this.caseClassOfModuleClass get clazz match {
+ case Some(cdef) =>
+ addApplyUnapply(cdef, templateNamer)
+ caseClassOfModuleClass -= clazz
+ case None =>
+ }
}
// add the copy method to case classes; this needs to be done here, not in SyntheticMethods, because
// the namer phase must traverse this copy method to create default getters for its parameters.
- Namers.this.caseClassOfModuleClass get clazz.companionModule.moduleClass match {
- case Some(cdef) =>
- def hasCopy(decls: Scope) = {
- decls.iterator exists (_.name == nme.copy)
- }
- if (!hasCopy(decls) &&
- !parents.exists(p => hasCopy(p.typeSymbol.info.decls)) &&
- !parents.flatMap(_.baseClasses).distinct.exists(bc => hasCopy(bc.info.decls)))
- addCopyMethod(cdef, templateNamer)
- case None =>
+ // here, clazz is the ClassSymbol of the case class (not the module).
+ // @check: this seems to work only if the type completer of the class runs before the one of the
+ // module class: the one from the module class removes the entry form caseClassOfModuleClass (see above).
+ if (clazz.isClass && !clazz.hasFlag(MODULE)) {
+ Namers.this.caseClassOfModuleClass get companionModuleOf(clazz).moduleClass match {
+ case Some(cdef) =>
+ def hasCopy(decls: Scope) = {
+ decls.iterator exists (_.name == nme.copy)
+ }
+ if (!hasCopy(decls) &&
+ !parents.exists(p => hasCopy(p.typeSymbol.info.decls)) &&
+ !parents.flatMap(_.baseClasses).distinct.exists(bc => hasCopy(bc.info.decls)))
+ addCopyMethod(cdef, templateNamer)
+ case None =>
+ }
}
- // if default getters (for constructor defaults) need to be added to that module,
- // here's the namer to use
+ // if default getters (for constructor defaults) need to be added to that module, here's the namer
+ // to use. clazz is the ModuleClass. sourceModule works also for classes defined in methods.
val module = clazz.sourceModule
if (classAndNamerOfModule contains module) {
val (cdef, _) = classAndNamerOfModule(module)
@@ -947,6 +965,7 @@ trait Namers { self: Analyzer =>
if (vparamss == List(Nil) && baseParamss.isEmpty) baseParamss = List(Nil)
assert(!overrides || vparamss.length == baseParamss.length, ""+ meth.fullName + ", "+ overridden.fullName)
+ // cache the namer used for entering the default getter symbols
var ownerNamer: Option[Namer] = None
var moduleNamer: Option[(ClassDef, Namer)] = None
@@ -978,7 +997,7 @@ trait Namers { self: Analyzer =>
val parentNamer = if (isConstr) {
val (cdef, nmr) = moduleNamer.getOrElse {
- val module = meth.owner.companionModule
+ val module = companionModuleOf(meth.owner)
module.initialize // call type completer (typedTemplate), adds the
// module's templateNamer to classAndNamerOfModule
val (cdef, nmr) = classAndNamerOfModule(module)
@@ -1029,7 +1048,8 @@ trait Namers { self: Analyzer =>
Modifiers(meth.flags & (PRIVATE | PROTECTED | FINAL)) | SYNTHETIC | DEFAULTPARAM | oflag,
name, deftParams, defvParamss, defTpt, defRhs)
}
- meth.owner.resetFlag(INTERFACE) // there's a concrete member now
+ if (!isConstr)
+ meth.owner.resetFlag(INTERFACE) // there's a concrete member now
val default = parentNamer.enterSyntheticSym(defaultTree)
} else if (baseHasDefault) {
// the parameter does not have a default itself, but the corresponding parameter
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
index 89b4f910e5..18102a8bb4 100644
--- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
@@ -187,10 +187,21 @@ trait NamesDefaults { self: Analyzer =>
baseFun1 match {
// constructor calls
- case Select(New(TypeTree()), _) if isConstr =>
- blockWithoutQualifier(None)
- case Select(TypeApply(New(TypeTree()), _), _) if isConstr =>
- blockWithoutQualifier(None)
+ case Select(New(tp @ TypeTree()), _) if isConstr =>
+ // fixes #3338. Same qualifier for selecting the companion object as for the class.
+ val dq = tp.tpe match {
+ case TypeRef(pre, _, _) if (!pre.typeSymbol.isEmptyPackageClass) =>
+ moduleQual(tp.pos, mod => gen.mkAttributedSelect(gen.mkAttributedQualifier(pre), mod))
+ case _ => None
+ }
+ blockWithoutQualifier(dq)
+ case Select(TypeApply(New(tp @ TypeTree()), _), _) if isConstr =>
+ val dq = tp.tpe match {
+ case TypeRef(pre, _, _) if (!pre.typeSymbol.isEmptyPackageClass) =>
+ moduleQual(tp.pos, mod => gen.mkAttributedSelect(gen.mkAttributedQualifier(pre), mod))
+ case _ => None
+ }
+ blockWithoutQualifier(dq)
case Select(New(Ident(_)), _) if isConstr =>
blockWithoutQualifier(None)
@@ -350,8 +361,11 @@ trait NamesDefaults { self: Analyzer =>
if (missing forall (_.hasFlag(DEFAULTPARAM))) {
val defaultArgs = missing map (p => {
var default1 = qual match {
- case Some(q) => gen.mkAttributedSelect(q.duplicate, defaultGetter(p, context))
- case None => gen.mkAttributedRef(defaultGetter(p, context))
+ case Some(q) => gen.mkAttributedSelect(q.duplicate, defaultGetter(p, context)._1)
+ case None =>
+ val (m, q) = defaultGetter(p, context)
+ if (q.isDefined) gen.mkAttributedSelect(q.get, m)
+ else gen.mkAttributedRef(m)
}
default1 = if (targs.isEmpty) default1
else TypeApply(default1, targs.map(_.duplicate))
@@ -369,35 +383,32 @@ trait NamesDefaults { self: Analyzer =>
/**
* For a parameter with default argument, find the method symbol of
- * the default getter.
+ * the default getter. Can return a qualifier tree for the selecting
+ * the method's symbol (part of #3334 fix).
*/
- def defaultGetter(param: Symbol, context: Context) = {
+ def defaultGetter(param: Symbol, context: Context): (Symbol, Option[Tree]) = {
val i = param.owner.paramss.flatten.findIndexOf(p => p.name == param.name) + 1
if (i > 0) {
if (param.owner.isConstructor) {
val defGetterName = "init$default$"+ i
- param.owner.owner.companionModule.info.member(defGetterName)
+ var mod = param.owner.owner.companionModule
+ // if the class's owner is a method, .companionModule does not work
+ if (mod == NoSymbol)
+ mod = context.lookup(param.owner.owner.name.toTermName, param.owner.owner.owner)
+ (mod.info.member(defGetterName), Some(gen.mkAttributedRef(mod)))
} else {
val defGetterName = param.owner.name +"$default$"+ i
+ // isClass also works for methods in objects, owner is the ModuleClassSymbol
if (param.owner.owner.isClass) {
// .toInterface: otherwise we get the method symbol of the impl class
- param.owner.owner.toInterface.info.member(defGetterName)
+ (param.owner.owner.toInterface.info.member(defGetterName), None)
} else {
// the owner of the method is another method. find the default
// getter in the context.
- var res: Symbol = NoSymbol
- var ctx = context
- while(res == NoSymbol && ctx.outer != ctx) {
- val s = ctx.scope.lookup(defGetterName)
- if (s != NoSymbol && s.owner == param.owner.owner)
- res = s
- else
- ctx = ctx.outer
- }
- res
+ (context.lookup(defGetterName, param.owner.owner), None)
}
}
- } else NoSymbol
+ } else (NoSymbol, None)
}
/**
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 003a173892..bd8482cd67 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -971,17 +971,20 @@ abstract class RefChecks extends InfoTransform {
private def checkAnnotations(tpes: List[Type], pos: Position) = tpes foreach (tp => checkTypeRef(tp, pos))
private def doTypeTraversal(tree: Tree)(f: Type => Unit) = if (!inPattern) tree.tpe foreach f
- private def applyRefchecksToAnnotations(tree: Tree) = tree match {
- case m: MemberDef =>
- checkAnnotations(m.symbol.annotations map (_.atp), tree.pos)
- transformTrees(m.symbol.annotations.flatMap(_.args))
- case TypeTree() => doTypeTraversal(tree) {
- case AnnotatedType(annots, _, _) =>
- checkAnnotations(annots map (_.atp), tree.pos)
- transformTrees(annots.flatMap(_.args))
+ private def applyRefchecksToAnnotations(tree: Tree) = {
+ def applyChecks(annots: List[AnnotationInfo]) = {
+ checkAnnotations(annots map (_.atp), tree.pos)
+ transformTrees(annots flatMap (_.args))
+ }
+
+ tree match {
+ case m: MemberDef => applyChecks(m.symbol.annotations)
+ case TypeTree() => doTypeTraversal(tree) {
+ case AnnotatedType(annots, _, _) => applyChecks(annots)
+ case _ =>
+ }
case _ =>
}
- case _ =>
}
private def transformCaseApply(tree: Tree, ifNot: => Unit) = {
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index 6f5175c0ea..8a7f4b0958 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -54,7 +54,11 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
private def checkPackedConforms(tree: Tree, pt: Type): Tree = {
if (tree.tpe exists (_.typeSymbol.isExistentialSkolem)) {
val packed = localTyper.packedType(tree, NoSymbol)
- if (!(packed <:< pt)) localTyper.infer.typeError(tree.pos, packed, pt)
+ if (!(packed <:< pt)) {
+ val errorContext = localTyper.context.make(localTyper.context.tree)
+ errorContext.reportGeneralErrors = true
+ analyzer.newTyper(errorContext).infer.typeError(tree.pos, packed, pt)
+ }
}
tree
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
new file mode 100644
index 0000000000..1166f62ddb
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
@@ -0,0 +1,268 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2010 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package typechecker
+
+import scala.collection.mutable
+import scala.collection.mutable.ListBuffer
+import scala.util.control.ControlThrowable
+import scala.util.control.Exception.ultimately
+import symtab.Flags._
+import PartialFunction._
+
+/** An interface to enable higher configurability of diagnostic messages
+ * regarding type errors. This is barely a beginning as error messages are
+ * distributed far and wide across the codebase. The plan is to partition
+ * error messages into some broad groups and provide some mechanism for
+ * being more or less verbose on a selective basis. Possible groups include
+ * such examples as
+ *
+ * arity errors
+ * kind errors
+ * variance errors
+ * ambiguity errors
+ * volatility/stability errors
+ * implementation restrictions
+ *
+ * And more, and there is plenty of overlap, so it'll be a process.
+ *
+ * @author Paul Phillips
+ * @version 1.0
+ */
+trait TypeDiagnostics {
+ self: Analyzer =>
+
+ import global._
+ import definitions._
+ import global.typer.infer
+
+ /** It can be quite difficult to know which of the many functions called "error"
+ * is being called at any given point in the compiler. To alleviate this I am
+ * renaming such functions inside this trait based on where it originated.
+ */
+ def inferError(pos: Position, msg: String) = infer.error(pos, msg)
+
+ /** The common situation of making sure nothing is erroneous could be
+ * nicer if Symbols, Types, and Trees all implemented some common interface
+ * in which isErroneous and similar would be placed.
+ */
+ def noErroneousTypes(tps: Type*) = tps forall (x => !x.isErroneous)
+ def noErroneousSyms(syms: Symbol*) = syms forall (x => !x.isErroneous)
+ def noErroneousTrees(trees: Tree*) = trees forall (x => !x.isErroneous)
+
+ /** A map of Positions to addendums - if an error involves a position in
+ * the map, the addendum should also be printed.
+ */
+ private var addendums = mutable.Map[Position, () => String]()
+
+ def setAddendum(pos: Position, msg: () => String) =
+ if (pos != NoPosition)
+ addendums(pos) = msg
+
+ def withAddendum(pos: Position) = (_: String) + addendums.getOrElse(pos, () => "")()
+
+ def decodeWithNamespace(name: Name): String = {
+ val prefix = if (name.isTypeName) "type " else "value "
+ prefix + name.decode
+ }
+
+ /** Does the positioned line assigned to t1 precede that of t2?
+ */
+ def linePrecedes(t1: Tree, t2: Tree) = t1.pos.isDefined && t1.pos.isDefined && t1.pos.line < t2.pos.line
+
+ def notAMember(sel: Tree, qual: Tree, name: Name) = {
+ def decoded = decodeWithNamespace(name)
+
+ def msg: String = name match {
+ case nme.CONSTRUCTOR => qual.tpe.widen+" does not have a constructor"
+ case _ =>
+ def memberOf = if (qual.tpe.typeSymbol.isTypeParameterOrSkolem) "type parameter " else ""
+ def possibleCause =
+ if (linePrecedes(qual, sel))
+ "\npossible cause: maybe a semicolon is missing before `"+decoded+"'?"
+ else
+ ""
+
+ decoded+" is not a member of "+ memberOf + qual.tpe.widen + possibleCause
+ }
+ inferError(sel.pos, withAddendum(qual.pos)(msg))
+ }
+
+ /** Only prints the parameter names if they're not synthetic,
+ * since "x$1: Int" does not offer any more information than "Int".
+ */
+ private def methodTypeErrorString(tp: Type) = tp match {
+ case mt @ MethodType(params, resultType) =>
+ def forString =
+ if (params exists (_.isSynthetic)) params map (_.tpe)
+ else params map (_.defString)
+
+ forString.mkString("(", ",", ")") + resultType
+ case x => x.toString
+ }
+
+ def alternatives(tree: Tree): List[Type] = tree.tpe match {
+ case OverloadedType(pre, alternatives) => alternatives map pre.memberType
+ case _ => Nil
+ }
+ def alternativesString(tree: Tree) =
+ alternatives(tree) map (x => " " + methodTypeErrorString(x)) mkString ("", " <and>\n", "\n")
+
+ def missingParameterTypeError(fun: Tree, vparam: ValDef) = {
+ val suffix = if (vparam.mods.isSynthetic) " for expanded function "+fun else ""
+
+ inferError(vparam.pos, "missing parameter type" + suffix)
+ ErrorType
+ }
+
+ def treeSymTypeMsg(tree: Tree): String = {
+ val sym = tree.symbol
+ def hasParams = tree.tpe.paramSectionCount > 0
+ def preResultString = if (hasParams) ": " else " of type "
+
+ def nullMessage = "expression of type " + tree.tpe
+ def overloadedMessage = "overloaded method " + sym + " with alternatives:\n" + alternativesString(tree)
+ def moduleMessage = "" + sym
+ def defaultMessage = moduleMessage + preResultString + tree.tpe
+ def applyMessage = defaultMessage + tree.symbol.locationString
+
+ if (sym == null) nullMessage
+ else if (sym.isOverloaded) overloadedMessage
+ else if (sym.isModule) moduleMessage
+ else if (sym.name == nme.apply) applyMessage
+ else defaultMessage
+ }
+
+ def applyErrorMsg(tree: Tree, msg: String, argtpes: List[Type], pt: Type) = {
+ def asParams(xs: List[Any]) = xs.mkString("(", ", ", ")")
+
+ def resType = if (isWildcard(pt)) "" else " with expected result type " + pt
+ def allTypes = (alternatives(tree) flatMap (_.paramTypes)) ++ argtpes :+ pt
+
+ withDisambiguation(allTypes: _*) {
+ treeSymTypeMsg(tree) + msg + asParams(argtpes) + resType
+ }
+ }
+
+ def disambiguate(ss: List[String]) = ss match {
+ case Nil => Nil
+ case s :: ss => s :: (ss map { case `s` => "(some other)"+s ; case x => x })
+ }
+
+ // todo: use also for other error messages
+ def existentialContext(tp: Type) = tp.existentialSkolems match {
+ case Nil => ""
+ case xs => " where " + (disambiguate(xs map (_.existentialToString)) mkString ", ")
+ }
+
+ def foundReqMsg(found: Type, req: Type): String =
+ withDisambiguation(found, req) {
+ ";\n found : " + found.toLongString + existentialContext(found) +
+ "\n required: " + req + existentialContext(req)
+ }
+
+ /** If two given types contain different type variables with the same name
+ * differentiate the names by including owner information. Also, if the
+ * type error is because of a conflict between two identically named
+ * classes and one is in package scala, fully qualify the name so one
+ * need not deduce why "java.util.Iterator" and "Iterator" don't match.
+ * Another disambiguation performed is to address the confusion present
+ * in the following snippet:
+ * def f[Int](x: Int) = x + 5.
+ */
+ def withDisambiguation[T](types: Type*)(op: => T): T = {
+ object SymExtractor {
+ def unapply(x: Any) = x match {
+ case t @ TypeRef(_, sym, _) => Some(t -> sym)
+ case t @ ConstantType(value) => Some(t -> t.underlying.typeSymbol)
+ case _ => None
+ }
+ }
+ val typerefs =
+ for (tp <- types.toList ; SymExtractor(t, sym) <- tp) yield
+ t -> sym
+
+ val savedNames = typerefs map { case (_, sym) => sym -> sym.name } toMap
+ def restoreNames = savedNames foreach { case (sym, name) => sym.name = name }
+
+ def isAlreadyAltered(sym: Symbol) = sym.name != savedNames(sym)
+
+ def modifyName(sym: Symbol)(f: String => String): Unit =
+ sym.name = newTypeName(f(sym.name.toString))
+
+ def scalaQualify(sym: Symbol) =
+ if (sym.owner.isScalaPackageClass)
+ modifyName(sym)("scala." + _)
+
+ def explainName(sym: Symbol) = {
+ scalaQualify(sym)
+
+ if (!isAlreadyAltered(sym))
+ modifyName(sym)(_ + "(in " + sym.owner + ")")
+ }
+
+ ultimately(restoreNames) {
+ for ((t1, sym1) <- typerefs ; (t2, sym2) <- typerefs ; if sym1 != sym2 && (sym1 isLess sym2)) {
+
+ if (t1.toString == t2.toString) { // type variable collisions
+ List(sym1, sym2) foreach explainName
+ if (sym1.owner == sym2.owner)
+ sym2.name = newTypeName("(some other)"+sym2.name)
+ }
+ else if (sym1.name == sym2.name) { // symbol name collisions
+ List(sym1, sym2) foreach { x =>
+ if (x.owner.isScalaPackageClass)
+ modifyName(x)("scala." + _)
+ else if (x.isTypeParameterOrSkolem)
+ explainName(x)
+ }
+ }
+ }
+
+ // performing the actual operation
+ op
+ }
+ }
+
+ trait TyperDiagnostics {
+ self: Typer =>
+
+ private def contextError(pos: Position, msg: String) = context.error(pos, msg)
+ private def contextError(pos: Position, err: Throwable) = context.error(pos, err)
+
+ def symWasOverloaded(sym: Symbol) = sym.owner.isClass && sym.owner.info.member(sym.name).isOverloaded
+ def cyclicAdjective(sym: Symbol) = if (symWasOverloaded(sym)) "overloaded" else "recursive"
+
+ /** Returns Some(msg) if the given tree is untyped apparently due
+ * to a cyclic reference, and None otherwise.
+ */
+ def cyclicReferenceMessage(sym: Symbol, tree: Tree) = condOpt(tree) {
+ case ValDef(_, _, tpt, _) if tpt.tpe == null => "recursive "+sym+" needs type"
+ case DefDef(_, _, _, _, tpt, _) if tpt.tpe == null => List(cyclicAdjective(sym), sym, "needs result type") mkString " "
+ }
+
+ /** Report a type error.
+ *
+ * @param pos0 The position where to report the error
+ * @param ex The exception that caused the error
+ */
+ def reportTypeError(pos: Position, ex: TypeError) {
+ if (ex.pos == NoPosition) ex.pos = pos
+ if (!context.reportGeneralErrors) throw ex
+ if (settings.debug.value) ex.printStackTrace()
+
+ ex match {
+ case CyclicReference(sym, info: TypeCompleter) =>
+ contextError(ex.pos, cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage())
+
+ if (sym == ObjectClass)
+ throw new FatalError("cannot redefine root "+sym)
+ case _ =>
+ contextError(ex.pos, ex)
+ }
+ }
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 3fe937f241..92dd368ac5 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -161,7 +161,7 @@ trait Typers { self: Analyzer =>
else mode
}
- abstract class Typer(context0: Context) {
+ abstract class Typer(context0: Context) extends TyperDiagnostics {
import context0.unit
val infer = new Inferencer(context0) {
@@ -252,35 +252,6 @@ trait Typers { self: Analyzer =>
private[typechecker] var context = context0
def context1 = context
- /** Report a type error.
- *
- * @param pos0 The position where to report the error
- * @param ex The exception that caused the error
- */
- def reportTypeError(pos: Position, ex: TypeError) {
- if (ex.pos == NoPosition) ex.pos = pos
- if (!context.reportGeneralErrors) throw ex
- if (settings.debug.value) ex.printStackTrace()
- ex match {
- case CyclicReference(sym, info: TypeCompleter) =>
- val msg =
- info.tree match {
- case ValDef(_, _, tpt, _) if (tpt.tpe eq null) =>
- "recursive "+sym+" needs type"
- case DefDef(_, _, _, _, tpt, _) if (tpt.tpe eq null) =>
- (if (sym.owner.isClass && sym.owner.info.member(sym.name).hasFlag(OVERLOADED)) "overloaded "
- else "recursive ")+sym+" needs result type"
- case _ =>
- ex.getMessage()
- }
- context.error(ex.pos, msg)
- if (sym == ObjectClass)
- throw new FatalError("cannot redefine root "+sym)
- case _ =>
- context.error(ex.pos, ex)
- }
- }
-
/** Check that <code>tree</code> is a stable expression.
*
* @param tree ...
@@ -397,7 +368,7 @@ trait Typers { self: Analyzer =>
error(pos, "methods with `*'-parameters cannot be converted to function values");
*/
if (restpe.isDependent)
- error(pos, "method with dependent type "+tpe+" cannot be converted to function value");
+ error(pos, "method with dependent type "+tpe+" cannot be converted to function value")
checkParamsConvertible(pos, restpe)
case _ =>
}
@@ -1230,7 +1201,7 @@ trait Typers { self: Analyzer =>
if (!ps.isEmpty && !superclazz.isSubClass(ps.head.typeSymbol))
error(parent.pos, "illegal inheritance; super"+superclazz+
"\n is not a subclass of the super"+ps.head.typeSymbol+
- "\n of the mixin " + psym);
+ "\n of the mixin " + psym)
} else {
error(parent.pos, psym+" needs to be a trait to be mixed in")
}
@@ -1352,6 +1323,7 @@ trait Typers { self: Analyzer =>
*/
def addGetterSetter(stat: Tree): List[Tree] = stat match {
case ValDef(mods, name, tpt, rhs)
+ // PRIVATE | LOCAL are fields generated for primary constructor arguments
if (mods.flags & (PRIVATE | LOCAL)) != (PRIVATE | LOCAL).toLong && !stat.symbol.isModuleVar =>
val isDeferred = mods hasFlag DEFERRED
@@ -1592,7 +1564,7 @@ trait Typers { self: Analyzer =>
* @param rhs ...
*/
def computeParamAliases(clazz: Symbol, vparamss: List[List[ValDef]], rhs: Tree) {
- if (settings.debug.value) log("computing param aliases for "+clazz+":"+clazz.primaryConstructor.tpe+":"+rhs);//debug
+ if (settings.debug.value) log("computing param aliases for "+clazz+":"+clazz.primaryConstructor.tpe+":"+rhs)//debug
def decompose(call: Tree): (Tree, List[Tree]) = call match {
case Apply(fn, args) =>
val (superConstr, args1) = decompose(fn)
@@ -1600,7 +1572,7 @@ trait Typers { self: Analyzer =>
val args2 = if (params.isEmpty || !isRepeatedParamType(params.last.tpe)) args
else args.take(params.length - 1) ::: List(EmptyTree)
if (args2.length != params.length)
- assert(false, "mismatch " + clazz + " " + (params map (_.tpe)) + " " + args2);//debug
+ assert(false, "mismatch " + clazz + " " + (params map (_.tpe)) + " " + args2)//debug
(superConstr, args1 ::: args2)
case Block(stats, expr) if !stats.isEmpty =>
decompose(stats.last)
@@ -1639,7 +1611,7 @@ trait Typers { self: Analyzer =>
ownAcc = ownAcc.accessed
if (!ownAcc.isVariable && !alias.accessed.isVariable) {
if (settings.debug.value)
- log("" + ownAcc + " has alias "+alias + alias.locationString);//debug
+ log("" + ownAcc + " has alias "+alias + alias.locationString) //debug
ownAcc.asInstanceOf[TermSymbol].setAlias(alias)
}
}
@@ -1676,77 +1648,6 @@ trait Typers { self: Analyzer =>
}
}
- /** does given name name an identifier visible at this point?
- *
- * @param name the given name
- * @return <code>true</code> if an identifier with the given name is visible.
- */
- def namesSomeIdent(name: Name): Boolean = namesWhatIdent(name).isDefined
-
- /** If this name returns a visible identifier, return its symbol.
- *
- * @param name the given name
- * @return <code>Some(sym)</code> if an ident is visible, None otherwise.
- */
- def namesWhatIdent(name: Name): Option[Symbol] = {
- var cx = context
- while (cx != NoContext) {
- val pre = cx.enclClass.prefix
- val defEntry = cx.scope.lookupEntry(name)
- if ((defEntry ne null) && reallyExists(defEntry.sym))
- return Some(defEntry.sym)
-
- cx = cx.enclClass
- (pre member name filter (sym => reallyExists(sym) && context.isAccessible(sym, pre, false))) match {
- case NoSymbol => cx = cx.outer
- case other => return Some(other)
- }
- }
- context.imports map (_ importedSymbol name) find (_ != NoSymbol)
- }
-
- /** Does this tree declare a val or def with the same name as one in scope?
- * This only catches identifiers in the same file, so more work is needed.
- *
- * @param tree the given tree
- * @param filt filter for any conflicting symbols found -- false means ignore
- */
- def checkShadowings(tree: Tree, filt: (Symbol) => Boolean = _ => true) {
- def sameFile(other: Symbol) =
- (tree.symbol != null) && tree.symbol.sourceFile == other.sourceFile
- def inFile(other: Symbol) =
- if (sameFile(other)) ""
- else if (other.sourceFile != null) "in %s ".format(other.sourceFile)
- else ""
-
- def positionStr(other: Symbol) = other.pos match {
- case NoPosition => inFile(other) match { case "" => "(location unknown) " ; case x => x }
- case pos => "%sat line %s\n%s".format(inFile(other), pos.line, pos.lineContent) + """ /* is shadowed by */"""
- }
- def include(v: ValOrDefDef, other: Symbol) = {
- // shadowing on the same line is a good bet for noise
- (v.pos == NoPosition || other.pos == NoPosition || v.pos.line != other.pos.line) &&
- // not likely we'll shadow a whole package without realizing it
- !other.isPackage &&
- // (v.symbol == null || !v.symbol.hasTransOwner(other)) &&
- filt(other)
- }
-
- tree match {
- // while I try to figure out how to limit the noise far enough to make this
- // genuinely useful, I'm setting minimum identifier length to 3 to omit all
- // those x's and i's we so enjoy reusing.
- case v: ValOrDefDef if v.name.toString.length > 2 =>
- namesWhatIdent(v.name) map { other =>
- if (include(v, other) && unit != null) {
- val fstr = "%s (%s) shadows usage %s"
- unit.warning(v.pos, fstr.format(v.name, v.tpt, positionStr(other)))
- }
- }
- case _ =>
- }
- }
-
def typedUseCase(useCase: UseCase) {
def stringParser(str: String): syntaxAnalyzer.Parser = {
val file = new BatchSourceFile(context.unit.source.file, str) {
@@ -1793,15 +1694,6 @@ trait Typers { self: Analyzer =>
def typedDefDef(ddef: DefDef): DefDef = {
val meth = ddef.symbol
- // If warnings are enabled, attempt to alert about variable shadowing. This only
- // catches method parameters shadowing identifiers declared in the same file, so more
- // work is needed. Most of the code here is to filter out false positives.
- def isAuxConstructor(sym: Symbol) = sym.isConstructor && !sym.isPrimaryConstructor
- if (settings.YwarnShadow.value && !isAuxConstructor(ddef.symbol)) {
- for (v <- ddef.vparamss.flatten ; if v.symbol != null && !(v.symbol hasFlag SYNTHETIC))
- checkShadowings(v, (sym => !sym.isDeferred && !sym.isMethod))
- }
-
reenterTypeParams(ddef.tparams)
reenterValueParams(ddef.vparamss)
@@ -1933,7 +1825,6 @@ trait Typers { self: Analyzer =>
while ((e ne null) && (e.sym ne stat.symbol)) e = e.tail
if (e eq null) context.scope.enter(stat.symbol)
}
- if (settings.YwarnShadow.value) checkShadowings(stat)
enterLabelDef(stat)
}
if (phaseId(currentPeriod) <= currentRun.typerPhase.id) {
@@ -2155,18 +2046,18 @@ trait Typers { self: Analyzer =>
!(accessed hasFlag ACCESSOR) && accessed.isPrivateLocal
def checkNoDoubleDefsAndAddSynthetics(stats: List[Tree]): List[Tree] = {
- val scope = if (inBlock) context.scope else context.owner.info.decls;
+ val scope = if (inBlock) context.scope else context.owner.info.decls
val newStats = new ListBuffer[Tree]
var needsCheck = true
var moreToAdd = true
while (moreToAdd) {
val initSize = scope.size
- var e = scope.elems;
+ var e = scope.elems
while ((e ne null) && e.owner == scope) {
// check no double def
if (needsCheck) {
- var e1 = scope.lookupNextEntry(e);
+ var e1 = scope.lookupNextEntry(e)
while ((e1 ne null) && e1.owner == scope) {
if (!accesses(e.sym, e1.sym) && !accesses(e1.sym, e.sym) &&
(e.sym.isType || inBlock || (e.sym.tpe matches e1.sym.tpe)))
@@ -2394,7 +2285,8 @@ trait Typers { self: Analyzer =>
val (allArgs, missing) = addDefaults(args, qual, targs, previousArgss, params, fun.pos.focus, context)
if (allArgs.length == formals.length) {
// useful when a default doesn't match parameter type, e.g. def f[T](x:T="a"); f[Int]()
- context.diagnostic = "Error occured in an application involving default arguments." :: context.diagnostic
+ val note = "Error occurred in an application involving default arguments."
+ if (!(context.diagnostic contains note)) context.diagnostic = note :: context.diagnostic
doTypedApply(tree, if (blockIsEmpty) fun else fun1, allArgs, mode, pt)
} else {
tryTupleApply.getOrElse {
@@ -2466,7 +2358,7 @@ trait Typers { self: Analyzer =>
inferExprInstance(fun, tparams, WildcardType, true)
doTypedApply(tree, fun, args, mode, pt)
} else {
- assert((mode & PATTERNmode) == 0); // this case cannot arise for patterns
+ assert((mode & PATTERNmode) == 0) // this case cannot arise for patterns
val lenientTargs = protoTypeArgs(tparams, formals, mt.resultApprox, pt)
val strictTargs = (lenientTargs, tparams).zipped map ((targ, tparam) =>
if (targ == WildcardType) tparam.tpe else targ) //@M TODO: should probably be .tpeHK
@@ -2490,7 +2382,7 @@ trait Typers { self: Analyzer =>
val args1 = (args, formals).zipped map typedArgToPoly
if (args1 exists (_.tpe.isError)) setError(tree)
else {
- if (settings.debug.value) log("infer method inst "+fun+", tparams = "+tparams+", args = "+args1.map(_.tpe)+", pt = "+pt+", lobounds = "+tparams.map(_.tpe.bounds.lo)+", parambounds = "+tparams.map(_.info));//debug
+ if (settings.debug.value) log("infer method inst "+fun+", tparams = "+tparams+", args = "+args1.map(_.tpe)+", pt = "+pt+", lobounds = "+tparams.map(_.tpe.bounds.lo)+", parambounds = "+tparams.map(_.info)) //debug
// define the undetparams which have been fixed by this param list, replace the corresponding symbols in "fun"
// returns those undetparams which have not been instantiated.
val undetparams = inferMethodInstance(fun, tparams, args1, pt)
@@ -3016,6 +2908,8 @@ trait Typers { self: Analyzer =>
* @return ...
*/
protected def typed1(tree: Tree, mode: Int, pt: Type): Tree = {
+ def isPatternMode = (mode & PATTERNmode) != 0
+
//Console.println("typed1("+tree.getClass()+","+Integer.toHexString(mode)+","+pt+")")
def ptOrLub(tps: List[Type]) = if (isFullyDefined(pt)) (pt, false) else weakLub(tps map (_.deconst))
@@ -3114,13 +3008,6 @@ trait Typers { self: Analyzer =>
if (vble == NoSymbol)
vble = context.owner.newValue(tree.pos, name)
if (vble.name.toTermName != nme.WILDCARD) {
-/*
- if (namesSomeIdent(vble.name))
- context.warning(tree.pos,
- "pattern variable"+vble.name+" shadows a value visible in the environment;\n"+
- "use backquotes `"+vble.name+"` if you mean to match against that value;\n" +
- "or rename the variable or use an explicit bind "+vble.name+"@_ to avoid this warning.")
-*/
if ((mode & ALTmode) != 0)
error(tree.pos, "illegal variable in pattern alternative")
vble = namer.enterInScope(vble)
@@ -3143,32 +3030,36 @@ trait Typers { self: Analyzer =>
}
def typedAssign(lhs: Tree, rhs: Tree): Tree = {
- val lhs1 = typed(lhs, EXPRmode | LHSmode, WildcardType)
- val varsym = lhs1.symbol
- if ((varsym ne null) && treeInfo.mayBeVarGetter(varsym))
+ val lhs1 = typed(lhs, EXPRmode | LHSmode, WildcardType)
+ val varsym = lhs1.symbol
+ def failMsg =
+ if (varsym != null && varsym.isValue) "reassignment to val"
+ else "assignment to non variable"
+
+ def fail = {
+ if (!lhs1.tpe.isError)
+ error(tree.pos, failMsg)
+
+ setError(tree)
+ }
+ if (varsym == null)
+ return fail
+
+ if (treeInfo.mayBeVarGetter(varsym)) {
lhs1 match {
case Select(qual, name) =>
- return typed(
- Apply(
- Select(qual, nme.getterToSetter(name)) setPos lhs.pos,
- List(rhs)) setPos tree.pos,
- mode, pt)
+ val sel = Select(qual, nme.getterToSetter(name)) setPos lhs.pos
+ val app = Apply(sel, List(rhs)) setPos tree.pos
+ return typed(app, mode, pt)
case _ =>
-
}
- if ((varsym ne null) && (varsym.isVariable || varsym.isValue && phase.erasedTypes)) {
+ }
+ if (varsym.isVariable || varsym.isValue && phase.erasedTypes) {
val rhs1 = typed(rhs, EXPRmode | BYVALmode, lhs1.tpe)
treeCopy.Assign(tree, lhs1, checkDead(rhs1)) setType UnitClass.tpe
- } else {
- if (!lhs1.tpe.isError) {
- //println(lhs1+" = "+rhs+" "+varsym+" "+mayBeVarGetter(varsym)+" "+varsym.ownerChain+" "+varsym.info)// DEBUG
- error(tree.pos,
- if ((varsym ne null) && varsym.isValue) "reassignment to val"
- else "assignment to non variable")
- }
- setError(tree)
}
+ else fail
}
def typedIf(cond: Tree, thenp: Tree, elsep: Tree) = {
@@ -3269,7 +3160,7 @@ trait Typers { self: Analyzer =>
pt != WildcardType &&
pt != ErrorType &&
isSubType(pt, DelegateClass.tpe)) =>
- val scalaCaller = newScalaCaller(pt);
+ val scalaCaller = newScalaCaller(pt)
addScalaCallerInfo(scalaCaller, expr1.symbol)
val n: Name = scalaCaller.name
val del = Ident(DelegateClass) setType DelegateClass.tpe
@@ -3277,7 +3168,7 @@ trait Typers { self: Analyzer =>
//val f1 = TypeApply(f, List(Ident(pt.symbol) setType pt))
val args: List[Tree] = if(expr1.symbol.isStatic) List(Literal(Constant(null)))
else List(qual) // where the scala-method is located
- val rhs = Apply(f, args);
+ val rhs = Apply(f, args)
typed(rhs)
case _ =>
adapt(expr1, mode, functionType(formals map (t => WildcardType), WildcardType))
@@ -3314,19 +3205,19 @@ trait Typers { self: Analyzer =>
t
case ex: TypeError =>
stopTimer(failedApplyNanos, start)
- def errorInResult(tree: Tree): Boolean = tree.pos == ex.pos || {
- tree match {
- case Block(_, r) => errorInResult(r)
- case Match(_, cases) => cases exists errorInResult
- case CaseDef(_, _, r) => errorInResult(r)
- case Annotated(_, r) => errorInResult(r)
- case If(_, t, e) => errorInResult(t) || errorInResult(e)
- case Try(b, catches, _) => errorInResult(b) || (catches exists errorInResult)
- case Typed(r, Function(List(), EmptyTree)) => errorInResult(r)
- case _ => false
- }
- }
- if (errorInResult(fun) || (args exists errorInResult) || errorInResult(tree)) {
+ def treesInResult(tree: Tree): List[Tree] = tree :: (tree match {
+ case Block(_, r) => treesInResult(r)
+ case Match(_, cases) => cases
+ case CaseDef(_, _, r) => treesInResult(r)
+ case Annotated(_, r) => treesInResult(r)
+ case If(_, t, e) => treesInResult(t) ++ treesInResult(e)
+ case Try(b, catches, _) => treesInResult(b) ++ catches
+ case Typed(r, Function(Nil, EmptyTree)) => treesInResult(r)
+ case _ => Nil
+ })
+ def errorInResult(tree: Tree) = treesInResult(tree) exists (_.pos == ex.pos)
+
+ if (fun :: tree :: args exists errorInResult) {
if (printTypings) println("second try for: "+fun+" and "+args)
val Select(qual, name) = fun
val args1 = tryTypedArgs(args, argMode(fun, mode), ex)
@@ -3347,11 +3238,11 @@ trait Typers { self: Analyzer =>
def typedApply(fun: Tree, args: List[Tree]) = {
val stableApplication = (fun.symbol ne null) && fun.symbol.isMethod && fun.symbol.isStable
- if (stableApplication && (mode & PATTERNmode) != 0) {
+ if (stableApplication && isPatternMode) {
// treat stable function applications f() as expressions.
typed1(tree, mode & ~PATTERNmode | EXPRmode, pt)
} else {
- val funpt = if ((mode & PATTERNmode) != 0) pt else WildcardType
+ val funpt = if (isPatternMode) pt else WildcardType
val appStart = startTimer(failedApplyNanos)
val opeqStart = startTimer(failedOpEqNanos)
silent(_.typed(fun, funMode(mode), funpt)) match {
@@ -3392,7 +3283,7 @@ trait Typers { self: Analyzer =>
case ex: TypeError =>
fun match {
case Select(qual, name)
- if (mode & PATTERNmode) == 0 && nme.isOpAssignmentName(name.decode) =>
+ if !isPatternMode && nme.isOpAssignmentName(name.decode) =>
val qual1 = typedQualifier(qual)
if (treeInfo.isVariableOrGetter(qual1)) {
stopTimer(failedOpEqNanos, opeqStart)
@@ -3422,31 +3313,41 @@ trait Typers { self: Analyzer =>
Apply(
Select(vble.duplicate, prefix) setPos fun.pos.focus, args) setPos tree.pos.makeTransparent
) setPos tree.pos
+
+ def mkUpdate(table: Tree, indices: List[Tree]) = {
+ gen.evalOnceAll(table :: indices, context.owner, context.unit) { ts =>
+ val tab = ts.head
+ val is = ts.tail
+ Apply(
+ Select(tab(), nme.update) setPos table.pos,
+ ((is map (i => i())) ::: List(
+ Apply(
+ Select(
+ Apply(
+ Select(tab(), nme.apply) setPos table.pos,
+ is map (i => i())) setPos qual.pos,
+ prefix) setPos fun.pos,
+ args) setPos tree.pos)
+ )
+ ) setPos tree.pos
+ }
+ }
+
val tree1 = qual match {
+ case Ident(_) =>
+ mkAssign(qual)
+
case Select(qualqual, vname) =>
gen.evalOnce(qualqual, context.owner, context.unit) { qq =>
val qq1 = qq()
mkAssign(Select(qq1, vname) setPos qual.pos)
}
- case Apply(Select(table, nme.apply), indices) =>
- gen.evalOnceAll(table :: indices, context.owner, context.unit) { ts =>
- val tab = ts.head
- val is = ts.tail
- Apply(
- Select(tab(), nme.update) setPos table.pos,
- ((is map (i => i())) ::: List(
- Apply(
- Select(
- Apply(
- Select(tab(), nme.apply) setPos table.pos,
- is map (i => i())) setPos qual.pos,
- prefix) setPos fun.pos,
- args) setPos tree.pos)
- )
- ) setPos tree.pos
- }
- case Ident(_) =>
- mkAssign(qual)
+
+ case Apply(fn, indices) =>
+ treeInfo.methPart(fn) match {
+ case Select(table, nme.apply) => mkUpdate(table, indices)
+ case _ => errorTree(qual, "Unexpected tree during assignment conversion.")
+ }
}
typed1(tree1, mode, pt)
/*
@@ -3559,19 +3460,9 @@ trait Typers { self: Analyzer =>
if (name == nme.ERROR && onlyPresentation)
return makeErrorTree
- if (!qual.tpe.widen.isErroneous) {
- error(tree.pos,
- if (name == nme.CONSTRUCTOR)
- qual.tpe.widen+" does not have a constructor"
- else
- decode(name)+" is not a member of "+
- (if (qual.tpe.typeSymbol.isTypeParameterOrSkolem) "type parameter " else "") +
- qual.tpe.widen +
- (if ((context.unit ne null) && // Martin: why is this condition needed?
- qual.pos.isDefined && tree.pos.isDefined && qual.pos.line < tree.pos.line)
- "\npossible cause: maybe a semicolon is missing before `"+decode(name)+"'?"
- else ""))
- }
+ if (!qual.tpe.widen.isErroneous)
+ notAMember(tree, qual, name)
+
if (onlyPresentation) makeErrorTree else setError(tree)
} else {
val tree1 = tree match {
@@ -3647,8 +3538,8 @@ trait Typers { self: Analyzer =>
val symDepth = if (defEntry eq null) cx.depth
else cx.depth - (cx.scope.nestingLevel - defEntry.owner.nestingLevel)
- var impSym: Symbol = NoSymbol; // the imported symbol
- var imports = context.imports; // impSym != NoSymbol => it is imported from imports.head
+ var impSym: Symbol = NoSymbol // the imported symbol
+ var imports = context.imports // impSym != NoSymbol => it is imported from imports.head
while (!reallyExists(impSym) && !imports.isEmpty && imports.head.depth > symDepth) {
impSym = imports.head.importedSymbol(name)
if (!impSym.exists) imports = imports.tail
@@ -3711,7 +3602,7 @@ trait Typers { self: Analyzer =>
if (settings.debug.value) {
log(context.imports)//debug
}
- error(tree.pos, "not found: "+decode(name))
+ error(tree.pos, "not found: "+decodeWithNamespace(name))
defSym = context.owner.newErrorSymbol(name)
}
}
@@ -3779,7 +3670,7 @@ trait Typers { self: Analyzer =>
errorTree(tree, tpt1.tpe+" does not take type parameters")
} else {
//Console.println("\{tpt1}:\{tpt1.symbol}:\{tpt1.symbol.info}")
- if (settings.debug.value) Console.println(tpt1+":"+tpt1.symbol+":"+tpt1.symbol.info);//debug
+ if (settings.debug.value) Console.println(tpt1+":"+tpt1.symbol+":"+tpt1.symbol.info)//debug
errorTree(tree, "wrong number of type arguments for "+tpt1.tpe+", should be "+tparams.length)
}
}
@@ -3948,7 +3839,7 @@ trait Typers { self: Analyzer =>
val tpt1 = typedType(tpt, mode)
val expr1 = typed(expr, mode & stickyModes, tpt1.tpe.deconst)
val owntype =
- if ((mode & PATTERNmode) != 0) inferTypedPattern(tpt1.pos, tpt1.tpe, pt)
+ if (isPatternMode) inferTypedPattern(tpt1.pos, tpt1.tpe, pt)
else tpt1.tpe
//Console.println(typed pattern: "+tree+":"+", tp = "+tpt1.tpe+", pt = "+pt+" ==> "+owntype)//DEBUG
treeCopy.Typed(tree, expr1, tpt1) setType owntype
@@ -4146,15 +4037,15 @@ trait Typers { self: Analyzer =>
tree.tpe = null
if (tree.hasSymbol) tree.symbol = NoSymbol
}
- if (printTypings) println("typing "+tree+", pt = "+pt+", undetparams = "+context.undetparams+", implicits-enabled = "+context.implicitsEnabled+", silent = "+context.reportGeneralErrors); //DEBUG
+ if (printTypings) println("typing "+tree+", pt = "+pt+", undetparams = "+context.undetparams+", implicits-enabled = "+context.implicitsEnabled+", silent = "+context.reportGeneralErrors) //DEBUG
var tree1 = if (tree.tpe ne null) tree else typed1(tree, mode, dropExistential(pt))
- if (printTypings) println("typed "+tree1+":"+tree1.tpe+(if (isSingleType(tree1.tpe)) " with underlying "+tree1.tpe.widen else "")+", undetparams = "+context.undetparams+", pt = "+pt); //DEBUG
+ if (printTypings) println("typed "+tree1+":"+tree1.tpe+(if (isSingleType(tree1.tpe)) " with underlying "+tree1.tpe.widen else "")+", undetparams = "+context.undetparams+", pt = "+pt) //DEBUG
tree1.tpe = addAnnotations(tree1, tree1.tpe)
val result = if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt, tree)
- if (printTypings) println("adapted "+tree1+":"+tree1.tpe.widen+" to "+pt+", "+context.undetparams); //DEBUG
+ if (printTypings) println("adapted "+tree1+":"+tree1.tpe.widen+" to "+pt+", "+context.undetparams) //DEBUG
// for (t <- tree1.tpe) assert(t != WildcardType)
// if ((mode & TYPEmode) != 0) println("type: "+tree1+" has type "+tree1.tpe)
if (phase.id <= currentRun.typerPhase.id) signalDone(context.asInstanceOf[analyzer.Context], tree, result)
@@ -4162,7 +4053,7 @@ trait Typers { self: Analyzer =>
} catch {
case ex: TypeError =>
tree.tpe = null
- if (printTypings) println("caught "+ex+" in typed: "+tree);//DEBUG
+ if (printTypings) println("caught "+ex+" in typed: "+tree) //DEBUG
reportTypeError(tree.pos, ex)
setError(tree)
case ex: Exception =>
@@ -4170,7 +4061,7 @@ trait Typers { self: Analyzer =>
Console.println("exception when typing "+tree+", pt = "+pt)
if ((context ne null) && (context.unit ne null) &&
(context.unit.source ne null) && (tree ne null))
- logError("AT: " + (tree.pos).dbgString, ex);
+ logError("AT: " + (tree.pos).dbgString, ex)
throw ex
}
finally {
diff --git a/src/compiler/scala/tools/nsc/util/Chars.scala b/src/compiler/scala/tools/nsc/util/Chars.scala
index 5a64f36eb4..562806b6eb 100755
--- a/src/compiler/scala/tools/nsc/util/Chars.scala
+++ b/src/compiler/scala/tools/nsc/util/Chars.scala
@@ -34,6 +34,17 @@ object Chars {
-1
}
+ /** Convert a character to a backslash-u escape */
+ def char2uescape(c: Char): String = {
+ var rest = c.toInt
+ val buf = new StringBuilder
+ for (i <- 1 to 4) {
+ buf ++= (rest % 16).toHexString
+ rest = rest / 16
+ }
+ "\\u" + buf.toString.reverse
+ }
+
/** Is character a line break? */
@inline def isLineBreakChar(c: Char) = (c: @switch) match {
case LF|FF|CR|SU => true
diff --git a/src/compiler/scala/tools/nsc/util/ShowPickled.scala b/src/compiler/scala/tools/nsc/util/ShowPickled.scala
index 740e42192b..b87d603570 100644
--- a/src/compiler/scala/tools/nsc/util/ShowPickled.scala
+++ b/src/compiler/scala/tools/nsc/util/ShowPickled.scala
@@ -13,6 +13,7 @@ import java.lang.Long.toHexString
import java.lang.Float.intBitsToFloat
import java.lang.Double.longBitsToDouble
+import cmd.program.Simple
import symtab.{ Flags, Names }
import scala.reflect.generic.{ PickleBuffer, PickleFormat }
import interpreter.ByteCode.scalaSigBytesForPath
@@ -288,15 +289,23 @@ object ShowPickled extends Names {
printFile(pickle, Console.out, bare)
}
+ private lazy val ShowPickledSpec =
+ Simple(
+ Simple.scalaProgramInfo("showPickled", "Usage: showPickled [--bare] <classname>"),
+ List("--bare" -> "suppress numbers in output"),
+ Nil,
+ null
+ )
+
/** Option --bare suppresses numbers so the output can be diffed.
*/
def main(args: Array[String]) {
- val parsed = cmd.CommandLine(args.toList, List("--bare"), Nil)
- def isBare = parsed isSet "--bare"
+ val runner = ShowPickledSpec instance args
+ import runner._
- parsed.residualArgs foreach { arg =>
+ residualArgs foreach { arg =>
(fromFile(arg) orElse fromName(arg)) match {
- case Some(pb) => show(arg, pb, isBare)
+ case Some(pb) => show(arg, pb, parsed isSet "--bare")
case _ => Console.println("Cannot read " + arg)
}
}
diff --git a/src/compiler/scala/tools/nsc/util/SourceFile.scala b/src/compiler/scala/tools/nsc/util/SourceFile.scala
index 57d2cc782f..f9f3c5e5fe 100644
--- a/src/compiler/scala/tools/nsc/util/SourceFile.scala
+++ b/src/compiler/scala/tools/nsc/util/SourceFile.scala
@@ -163,7 +163,6 @@ extends BatchSourceFile(name, contents)
override def positionInUltimateSource(position: Position) = {
if (!position.isDefined) super.positionInUltimateSource(position)
else {
- println("!!!")
var off = position.point
var compsLeft = components
// the search here has to be against the length of the files underlying the
@@ -171,7 +170,6 @@ extends BatchSourceFile(name, contents)
// less than the underlying length.) Otherwise we can and will overshoot the
// correct component and return a garbage position.
while (compsLeft.head.underlyingLength-1 <= off && !compsLeft.tail.isEmpty) {
- println("discarding "+compsLeft.head)
off = off - compsLeft.head.underlyingLength + 1
compsLeft = compsLeft.tail
}
diff --git a/src/library/scala/Array.scala b/src/library/scala/Array.scala
index f89e8b48a5..c9d929b88c 100644
--- a/src/library/scala/Array.scala
+++ b/src/library/scala/Array.scala
@@ -207,6 +207,7 @@ object Array extends FallbackArrayBuilding {
*/
def fill[T: ClassManifest](n: Int)(elem: => T): Array[T] = {
val b = newBuilder[T]
+ b.sizeHint(n)
var i = 0
while (i < n) {
b += elem
@@ -270,6 +271,7 @@ object Array extends FallbackArrayBuilding {
*/
def tabulate[T: ClassManifest](n: Int)(f: Int => T): Array[T] = {
val b = newBuilder[T]
+ b.sizeHint(n)
var i = 0
while (i < n) {
b += f(i)
@@ -343,6 +345,8 @@ object Array extends FallbackArrayBuilding {
def range(start: Int, end: Int, step: Int): Array[Int] = {
if (step == 0) throw new IllegalArgumentException("zero step")
val b = newBuilder[Int]
+ b.sizeHint(Range.count(start, end, step, false))
+
var i = start
while (if (step < 0) end < i else i < end) {
b += i
@@ -360,6 +364,7 @@ object Array extends FallbackArrayBuilding {
*/
def iterate[T: ClassManifest](start: T, len: Int)(f: T => T): Array[T] = {
val b = newBuilder[T]
+ b.sizeHint(len)
var acc = start
var i = 0
while (i < len) {
diff --git a/src/library/scala/collection/BitSet.scala b/src/library/scala/collection/BitSet.scala
index b43b681888..e362271f70 100644
--- a/src/library/scala/collection/BitSet.scala
+++ b/src/library/scala/collection/BitSet.scala
@@ -27,6 +27,8 @@ trait BitSet extends Set[Int]
*/
object BitSet extends BitSetFactory[BitSet] {
val empty: BitSet = immutable.BitSet.empty
+ def newBuilder = immutable.BitSet.newBuilder
+
/** $canBuildFromInfo */
implicit def canBuildFrom: CanBuildFrom[BitSet, Int, BitSet] = bitsetCanBuildFrom
}
diff --git a/src/library/scala/collection/BitSetLike.scala b/src/library/scala/collection/BitSetLike.scala
index 3028cca6eb..b4e9682d88 100644
--- a/src/library/scala/collection/BitSetLike.scala
+++ b/src/library/scala/collection/BitSetLike.scala
@@ -25,7 +25,7 @@ import mutable.StringBuilder
*
* @define bitsetinfo
* Bitsets are sets of non-negative integers which are represented as
- * variable-size arrays of bits packed into 64-bit words. The size of a bitset is
+ * variable-size arrays of bits packed into 64-bit words. The memory footprint of a bitset is
* determined by the largest number stored in it.
* @author Martin Odersky
* @version 2.8
diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala
index 24c447b24b..5eca806933 100644
--- a/src/library/scala/collection/Iterator.scala
+++ b/src/library/scala/collection/Iterator.scala
@@ -11,8 +11,7 @@
package scala.collection
-import mutable.{Buffer, ArrayBuffer, ListBuffer, StringBuilder}
-import immutable.{List, Stream}
+import mutable.ArrayBuffer
import annotation.{ tailrec, migration }
/** The `Iterator` object provides various functions for
@@ -110,9 +109,15 @@ object Iterator {
* @return the iterator producing the infinite sequence of values `start, f(start), f(f(start)), ...`
*/
def iterate[T](start: T)(f: T => T): Iterator[T] = new Iterator[T] {
+ private[this] var first = true
private[this] var acc = start
def hasNext: Boolean = true
- def next(): T = { val res = acc ; acc = f(acc) ; res }
+ def next(): T = {
+ if (first) first = false
+ else acc = f(acc)
+
+ acc
+ }
}
/** Creates an infinite-length iterator which returns successive values from some start value.
diff --git a/src/library/scala/collection/SeqLike.scala b/src/library/scala/collection/SeqLike.scala
index b9ac28cb2d..d80539d0b0 100644
--- a/src/library/scala/collection/SeqLike.scala
+++ b/src/library/scala/collection/SeqLike.scala
@@ -20,6 +20,7 @@ import generic._
object SeqLike {
/** A KMP implementation, based on the undoubtedly reliable wikipedia entry.
+ *
* @author paulp
* @since 2.8
*/
@@ -72,7 +73,23 @@ object SeqLike {
None
}
- /** Waiting for a doc comment from Paul
+ /** Finds a particular index at which one sequence occurs in another sequence.
+ * Both the source sequence and the target sequence are expressed in terms
+ * other sequences S' and T' with offset and length parameters. This
+ * function is designed to wrap the KMP machinery in a sufficiently general
+ * way that all library sequence searches can use it. It is unlikely you
+ * have cause to call it directly: prefer functions such as StringBuilder#indexOf
+ * and Seq#lastIndexOf.
+ *
+ * @param source the sequence to search in
+ * @param sourceOffset the starting offset in source
+ * @param sourceCount the length beyond sourceOffset to search
+ * @param target the sequence being searched for
+ * @param targetOffset the starting offset in target
+ * @param targetCount the length beyond targetOffset which makes up the target string
+ * @param fromIndex the smallest index at which the target sequence may start
+ *
+ * @return the applicable index in source where target exists, or -1 if not found
*/
def indexOf[B](
source: Seq[B], sourceOffset: Int, sourceCount: Int,
@@ -83,7 +100,10 @@ object SeqLike {
case Some(x) => x + fromIndex
}
- /** Waiting for a doc comment from Paul
+ /** Finds a particular index at which one sequence occurs in another sequence.
+ * Like indexOf, but finds the latest occurrence rather than earliest.
+ *
+ * @see SeqLike#indexOf
*/
def lastIndexOf[B](
source: Seq[B], sourceOffset: Int, sourceCount: Int,
diff --git a/src/library/scala/collection/Set.scala b/src/library/scala/collection/Set.scala
index 034d9f1705..f1c1e43731 100644
--- a/src/library/scala/collection/Set.scala
+++ b/src/library/scala/collection/Set.scala
@@ -37,6 +37,7 @@ trait Set[A] extends (A => Boolean)
* @define Coll Set
*/
object Set extends SetFactory[Set] {
+ def newBuilder[A] = immutable.Set.newBuilder[A]
override def empty[A]: Set[A] = immutable.Set.empty[A]
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Set[A]] = setCanBuildFrom[A]
}
diff --git a/src/library/scala/collection/generic/BitSetFactory.scala b/src/library/scala/collection/generic/BitSetFactory.scala
index 5679b25351..08cf7bd0e0 100644
--- a/src/library/scala/collection/generic/BitSetFactory.scala
+++ b/src/library/scala/collection/generic/BitSetFactory.scala
@@ -13,7 +13,7 @@ package scala.collection
package generic
import scala.collection._
-import mutable.{Builder, AddingBuilder}
+import mutable.Builder
/** @define coll collection
* @define Coll Traversable
@@ -28,8 +28,8 @@ import mutable.{Builder, AddingBuilder}
* The standard `CanBuildFrom` instance for bitsets.
*/
trait BitSetFactory[Coll <: BitSet with BitSetLike[Coll]] {
- def newBuilder: Builder[Int, Coll] = new AddingBuilder[Int, Coll](empty)
def empty: Coll
+ def newBuilder: Builder[Int, Coll]
def apply(elems: Int*): Coll = (empty /: elems) (_ + _)
def bitsetCanBuildFrom = new CanBuildFrom[Coll, Int, Coll] {
def apply(from: Coll) = newBuilder
diff --git a/src/library/scala/concurrent/AsyncInvokable.scala b/src/library/scala/collection/generic/ImmutableSetFactory.scala
index ac465c7fe5..a551786f25 100644
--- a/src/library/scala/concurrent/AsyncInvokable.scala
+++ b/src/library/scala/collection/generic/ImmutableSetFactory.scala
@@ -6,19 +6,13 @@
** |/ **
\* */
-// $Id$
+package scala.collection
+package generic
+import mutable.{ Builder, AddingBuilder }
-package scala.concurrent
-
-/** The <code>AsyncInvokable</code> trait...
- *
- * @author Philipp Haller
- */
-trait AsyncInvokable[-T, +R] {
-
- type Future[+S] <: () => S
-
- def !!(task: T): Future[R]
+abstract class ImmutableSetFactory[CC[X] <: immutable.Set[X] with SetLike[X, CC[X]]]
+ extends SetFactory[CC] {
+ def newBuilder[A]: Builder[A, CC[A]] = new AddingBuilder[A, CC[A]](empty[A])
}
diff --git a/src/library/scala/collection/generic/MutableSetFactory.scala b/src/library/scala/collection/generic/MutableSetFactory.scala
new file mode 100644
index 0000000000..28b5fdd897
--- /dev/null
+++ b/src/library/scala/collection/generic/MutableSetFactory.scala
@@ -0,0 +1,18 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2010, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.collection
+package generic
+
+import mutable.{ Builder, GrowingBuilder }
+
+abstract class MutableSetFactory[CC[X] <: mutable.Set[X] with mutable.SetLike[X, CC[X]]]
+ extends SetFactory[CC] {
+
+ def newBuilder[A]: Builder[A, CC[A]] = new GrowingBuilder[A, CC[A]](empty[A])
+}
diff --git a/src/library/scala/collection/generic/SetFactory.scala b/src/library/scala/collection/generic/SetFactory.scala
index 1c4ec3e7e3..d43664bd39 100644
--- a/src/library/scala/collection/generic/SetFactory.scala
+++ b/src/library/scala/collection/generic/SetFactory.scala
@@ -12,7 +12,7 @@
package scala.collection
package generic
-import mutable.{Builder, AddingBuilder}
+import mutable.Builder
/** A template for companion objects of `Set` and subclasses thereof.
*
@@ -34,7 +34,7 @@ import mutable.{Builder, AddingBuilder}
abstract class SetFactory[CC[X] <: Set[X] with SetLike[X, CC[X]]]
extends GenericCompanion[CC] {
- def newBuilder[A]: Builder[A, CC[A]] = new AddingBuilder[A, CC[A]](empty[A])
+ def newBuilder[A]: Builder[A, CC[A]]
/** $setCanBuildFromInfo
*/
diff --git a/src/library/scala/collection/generic/TraversableFactory.scala b/src/library/scala/collection/generic/TraversableFactory.scala
index b7fda70922..ffc4f16466 100644
--- a/src/library/scala/collection/generic/TraversableFactory.scala
+++ b/src/library/scala/collection/generic/TraversableFactory.scala
@@ -62,6 +62,10 @@ abstract class TraversableFactory[CC[X] <: Traversable[X] with GenericTraversabl
*/
def concat[A](xss: Traversable[A]*): CC[A] = {
val b = newBuilder[A]
+ // At present we're using IndexedSeq as a proxy for "has a cheap size method".
+ if (xss forall (_.isInstanceOf[IndexedSeq[_]]))
+ b.sizeHint(xss map (_.size) sum)
+
for (xs <- xss) b ++= xs
b.result
}
@@ -73,6 +77,7 @@ abstract class TraversableFactory[CC[X] <: Traversable[X] with GenericTraversabl
*/
def fill[A](n: Int)(elem: => A): CC[A] = {
val b = newBuilder[A]
+ b.sizeHint(n)
var i = 0
while (i < n) {
b += elem
@@ -130,6 +135,7 @@ abstract class TraversableFactory[CC[X] <: Traversable[X] with GenericTraversabl
*/
def tabulate[A](n: Int)(f: Int => A): CC[A] = {
val b = newBuilder[A]
+ b.sizeHint(n)
var i = 0
while (i < n) {
b += f(i)
@@ -201,6 +207,7 @@ abstract class TraversableFactory[CC[X] <: Traversable[X] with GenericTraversabl
def range(start: Int, end: Int, step: Int): CC[Int] = {
if (step == 0) throw new IllegalArgumentException("zero step")
val b = newBuilder[Int]
+ b.sizeHint(Range.count(start, end, step, false))
var i = start
while (if (step < 0) end < i else i < end) {
b += i
@@ -218,6 +225,7 @@ abstract class TraversableFactory[CC[X] <: Traversable[X] with GenericTraversabl
*/
def iterate[A](start: A, len: Int)(f: A => A): CC[A] = {
val b = newBuilder[A]
+ b.sizeHint(len)
var acc = start
var i = 0
while (i < len) {
diff --git a/src/library/scala/collection/immutable/BitSet.scala b/src/library/scala/collection/immutable/BitSet.scala
index 9b801f26cb..8fa23c3ddf 100644
--- a/src/library/scala/collection/immutable/BitSet.scala
+++ b/src/library/scala/collection/immutable/BitSet.scala
@@ -14,6 +14,7 @@ package immutable
import generic._
import BitSetLike.{LogWL, updateArray}
+import mutable.{ Builder, AddingBuilder }
/** A class for immutable bitsets.
* $bitsetinfo
@@ -60,10 +61,12 @@ abstract class BitSet extends Set[Int]
* @define coll immutable bitset
*/
object BitSet extends BitSetFactory[BitSet] {
-
/** The empty bitset */
val empty: BitSet = new BitSet1(0L)
+ /** An adding builder for immutable Sets. */
+ def newBuilder: Builder[Int, BitSet] = new AddingBuilder[Int, BitSet](empty)
+
/** $bitsetCanBuildFrom */
implicit def canBuildFrom: CanBuildFrom[BitSet, Int, BitSet] = bitsetCanBuildFrom
diff --git a/src/library/scala/collection/immutable/DefaultMap.scala b/src/library/scala/collection/immutable/DefaultMap.scala
index 667d86d352..4f36679119 100755
--- a/src/library/scala/collection/immutable/DefaultMap.scala
+++ b/src/library/scala/collection/immutable/DefaultMap.scala
@@ -50,7 +50,7 @@ trait DefaultMap[A, +B] extends Map[A, B] { self =>
*/
override def - (key: A): Map[A, B] = {
val b = newBuilder
- b ++= this filter (key !=)
+ for (kv <- this ; if kv._1 != key) b += kv
b.result
}
}
diff --git a/src/library/scala/collection/immutable/HashSet.scala b/src/library/scala/collection/immutable/HashSet.scala
index 68da0cef50..481b1c3204 100644
--- a/src/library/scala/collection/immutable/HashSet.scala
+++ b/src/library/scala/collection/immutable/HashSet.scala
@@ -88,7 +88,7 @@ class HashSet[A] extends Set[A]
* @define mayNotTerminateInf
* @define willNotTerminateInf
*/
-object HashSet extends SetFactory[HashSet] {
+object HashSet extends ImmutableSetFactory[HashSet] {
/** $setCanBuildFromInfo */
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, HashSet[A]] = setCanBuildFrom[A]
override def empty[A]: HashSet[A] = EmptyHashSet.asInstanceOf[HashSet[A]]
diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala
index 4ce441ca55..f9937f6925 100644
--- a/src/library/scala/collection/immutable/List.scala
+++ b/src/library/scala/collection/immutable/List.scala
@@ -19,9 +19,9 @@ import annotation.tailrec
/** A class for immutable linked lists representing ordered collections
* of elements of type.
*
- * This class comes with two implementing case classes `scala.Nil`
- * and `scala.::` that implement the abstract members `isEmpty`,
- * `head` and `tail`.
+ * This class comes with two implementing case classes `scala.Nil`
+ * and `scala.::` that implement the abstract members `isEmpty`,
+ * `head` and `tail`.
*
* @author Martin Odersky and others
* @version 2.8
diff --git a/src/library/scala/collection/immutable/ListSet.scala b/src/library/scala/collection/immutable/ListSet.scala
index 2a202df9ef..979fdff552 100644
--- a/src/library/scala/collection/immutable/ListSet.scala
+++ b/src/library/scala/collection/immutable/ListSet.scala
@@ -19,7 +19,7 @@ import generic._
* @define coll immutable list set
* @since 1
*/
-object ListSet extends SetFactory[ListSet] {
+object ListSet extends ImmutableSetFactory[ListSet] {
/** setCanBuildFromInfo */
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, ListSet[A]] = setCanBuildFrom[A]
override def empty[A] = new ListSet[A]
diff --git a/src/library/scala/collection/immutable/Queue.scala b/src/library/scala/collection/immutable/Queue.scala
index 7a903cb201..7ffceb6be8 100644
--- a/src/library/scala/collection/immutable/Queue.scala
+++ b/src/library/scala/collection/immutable/Queue.scala
@@ -14,6 +14,7 @@ package immutable
import generic._
import mutable.{ Builder, ListBuffer }
+import annotation.tailrec
/** `Queue` objects implement data structures that allow to
* insert and retrieve elements in a first-in-first-out (FIFO) manner.
@@ -29,9 +30,9 @@ import mutable.{ Builder, ListBuffer }
@serializable
@SerialVersionUID(-7622936493364270175L)
class Queue[+A] protected(protected val in: List[A], protected val out: List[A])
- extends Seq[A]
+ extends LinearSeq[A]
with GenericTraversableTemplate[A, Queue]
- with SeqLike[A, Queue[A]] {
+ with LinearSeqLike[A, Queue[A]] {
override def companion: GenericCompanion[Queue] = Queue
@@ -42,7 +43,7 @@ class Queue[+A] protected(protected val in: List[A], protected val out: List[A])
* @return the element at position `n` in this queue.
* @throws Predef.NoSuchElementException if the queue is too short.
*/
- def apply(n: Int): A = {
+ override def apply(n: Int): A = {
val len = out.length
if (n < len) out.apply(n)
else {
@@ -62,9 +63,19 @@ class Queue[+A] protected(protected val in: List[A], protected val out: List[A])
*/
override def isEmpty: Boolean = in.isEmpty && out.isEmpty
+ override def head: A =
+ if (out.nonEmpty) out.head
+ else if (in.nonEmpty) in.last
+ else throw new NoSuchElementException("head on empty queue")
+
+ override def tail: Queue[A] =
+ if (out.nonEmpty) new Queue(in, out.tail)
+ else if (in.nonEmpty) new Queue(Nil, in.reverse.tail)
+ else throw new NoSuchElementException("tail on empty queue")
+
/** Returns the length of the queue.
*/
- def length = in.length + out.length
+ override def length = in.length + out.length
/** Creates a new queue with element added at the end
* of the old queue.
@@ -101,7 +112,7 @@ class Queue[+A] protected(protected val in: List[A], protected val out: List[A])
* @param iter an iterable object
*/
def enqueue[B >: A](iter: Iterable[B]) =
- new Queue(iter.iterator.toList.reverse ::: in, out)
+ new Queue(iter.toList.reverse ::: in, out)
/** Returns a tuple with the first element in the queue,
* and a new queue with this element removed.
@@ -121,10 +132,7 @@ class Queue[+A] protected(protected val in: List[A], protected val out: List[A])
* @throws Predef.NoSuchElementException
* @return the first element.
*/
- def front: A =
- if (!out.isEmpty) out.head
- else if (!in.isEmpty) in.last
- else throw new NoSuchElementException("front on empty queue")
+ def front: A = head
/** Returns a string representation of this queue.
*/
diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala
index 8f1f7d58a6..0f20b1ea04 100644
--- a/src/library/scala/collection/immutable/Range.scala
+++ b/src/library/scala/collection/immutable/Range.scala
@@ -219,6 +219,23 @@ class Range(val start: Int, val end: Int, val step: Int) extends IndexedSeq[Int]
object Range {
private[immutable] val MAX_PRINT = 512 // some arbitrary value
+ /** Calculates the number of elements in a range given start, end, step, and
+ * whether or not it is inclusive. Returns -1 if parameters are invalid.
+ */
+ def count(start: Int, end: Int, step: Int): Int = count(start, end, step, false)
+ def count(start: Int, end: Int, step: Int, isInclusive: Boolean): Int = {
+ def last =
+ if (isInclusive && step < 0) end - 1
+ else if (isInclusive && step > 0) end + 1
+ else end
+
+ if (step == 0) -1
+ else if (start == end) { if (isInclusive) 1 else 0 }
+ else if (end > start != step > 0) -1
+ else if (step == 1 || step == -1) last - start
+ else ((last - start - 1) / step) + 1
+ }
+
class Inclusive(start: Int, end: Int, step: Int) extends Range(start, end, step) {
override def isInclusive = true
override protected def copy(start: Int, end: Int, step: Int): Range = new Inclusive(start, end, step)
diff --git a/src/library/scala/collection/immutable/Set.scala b/src/library/scala/collection/immutable/Set.scala
index 769ee37f6b..745b0034e8 100644
--- a/src/library/scala/collection/immutable/Set.scala
+++ b/src/library/scala/collection/immutable/Set.scala
@@ -36,7 +36,7 @@ trait Set[A] extends Iterable[A]
* @define Coll immutable.Set
* @define coll immutable set
*/
-object Set extends SetFactory[Set] {
+object Set extends ImmutableSetFactory[Set] {
/** $setCanBuildFromInfo */
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Set[A]] = setCanBuildFrom[A]
override def empty[A]: Set[A] = EmptySet.asInstanceOf[Set[A]]
diff --git a/src/library/scala/collection/immutable/Stack.scala b/src/library/scala/collection/immutable/Stack.scala
index 0323db7211..c90ab379af 100644
--- a/src/library/scala/collection/immutable/Stack.scala
+++ b/src/library/scala/collection/immutable/Stack.scala
@@ -48,7 +48,8 @@ object Stack extends SeqFactory[Stack] {
* @define willNotTerminateInf
*/
@serializable @SerialVersionUID(1976480595012942526L)
-class Stack[+A] protected (protected val elems: List[A]) extends LinearSeq[A]
+class Stack[+A] protected (protected val elems: List[A])
+ extends LinearSeq[A]
with GenericTraversableTemplate[A, Stack]
with LinearSeqOptimized[A, Stack[A]] {
override def companion: GenericCompanion[Stack] = Stack
diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala
index 50fa07c2cf..fbda0b918b 100644
--- a/src/library/scala/collection/immutable/Stream.scala
+++ b/src/library/scala/collection/immutable/Stream.scala
@@ -104,6 +104,16 @@ self =>
loop(this, "")
}
+ override def length: Int = {
+ var len = 0
+ var left = this
+ while (!left.isEmpty) {
+ len += 1
+ left = left.tail
+ }
+ len
+ }
+
/** It's an imperfect world, but at least we can bottle up the
* imperfection in a capsule.
*/
diff --git a/src/library/scala/collection/immutable/TreeSet.scala b/src/library/scala/collection/immutable/TreeSet.scala
index 7b1f71df5b..18c65dd373 100644
--- a/src/library/scala/collection/immutable/TreeSet.scala
+++ b/src/library/scala/collection/immutable/TreeSet.scala
@@ -13,7 +13,7 @@ package scala.collection
package immutable
import generic._
-import mutable.{Builder, AddingBuilder}
+import mutable.{ Builder, AddingBuilder }
/** $factoryInfo
* @define Coll immutable.TreeSet
diff --git a/src/library/scala/collection/mutable/AddingBuilder.scala b/src/library/scala/collection/mutable/AddingBuilder.scala
index 14636c9feb..54137b6a26 100644
--- a/src/library/scala/collection/mutable/AddingBuilder.scala
+++ b/src/library/scala/collection/mutable/AddingBuilder.scala
@@ -17,9 +17,12 @@ import generic._
* which adds an element to the collection.
*
* Collections are built from their empty element using this `+` method.
- * @param empty the empty element of the collection.
- * @tparam Elem the type of elements that get added to the builder.
- * @tparam To the type of the built collection.
+ * @param empty the empty element of the collection.
+ * @tparam Elem the type of elements that get added to the builder.
+ * @tparam To the type of the built collection.
+ *
+ * @note "efficient `+`" is not idle talk. Do not use this on mutable collections or any others
+ * for which `+` may perform an unshared copy! See GrowingBuilder comments for more.
*
* @author Martin Odersky
* @version 2.8
diff --git a/src/library/scala/collection/mutable/BitSet.scala b/src/library/scala/collection/mutable/BitSet.scala
index 5d0f5863ca..da3e95fce7 100644
--- a/src/library/scala/collection/mutable/BitSet.scala
+++ b/src/library/scala/collection/mutable/BitSet.scala
@@ -114,6 +114,10 @@ class BitSet(protected var elems: Array[Long]) extends Set[Int]
*/
object BitSet extends BitSetFactory[BitSet] {
def empty: BitSet = new BitSet
+
+ /** A growing builder for mutable Sets. */
+ def newBuilder: Builder[Int, BitSet] = new GrowingBuilder[Int, BitSet](empty)
+
/** $bitsetCanBuildFrom */
implicit def canBuildFrom: CanBuildFrom[BitSet, Int, BitSet] = bitsetCanBuildFrom
}
diff --git a/src/library/scala/collection/mutable/GrowingBuilder.scala b/src/library/scala/collection/mutable/GrowingBuilder.scala
index cd1c8bec8c..781753c24d 100644
--- a/src/library/scala/collection/mutable/GrowingBuilder.scala
+++ b/src/library/scala/collection/mutable/GrowingBuilder.scala
@@ -18,6 +18,11 @@ import generic._
* interacting surprisingly with any2stringadd thus driving '+' out of the `Seq`
* hierarchy. The tendrils of original sin should never be underestimated.
*
+ * Addendum: of even greater significance is that '+' on mutable collections now
+ * creates a new collection. This means using AddingBuilder on them will create
+ * a new intermediate collection for every element given to the builder, taking
+ * '+' from an O(1) to O(n) operation.
+ *
* @author Paul Phillips
* @version 2.8
* @since 2.8
diff --git a/src/library/scala/collection/mutable/HashSet.scala b/src/library/scala/collection/mutable/HashSet.scala
index 3d9dc3e55d..41f9a17dd6 100644
--- a/src/library/scala/collection/mutable/HashSet.scala
+++ b/src/library/scala/collection/mutable/HashSet.scala
@@ -79,7 +79,7 @@ class HashSet[A] extends Set[A]
* @define Coll mutable.HashSet
* @define coll mutable hash set
*/
-object HashSet extends SetFactory[HashSet] {
+object HashSet extends MutableSetFactory[HashSet] {
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, HashSet[A]] = setCanBuildFrom[A]
override def empty[A]: HashSet[A] = new HashSet[A]
}
diff --git a/src/library/scala/collection/mutable/IndexedSeqLike.scala b/src/library/scala/collection/mutable/IndexedSeqLike.scala
index 0c2d3f17bb..5e932effe0 100644
--- a/src/library/scala/collection/mutable/IndexedSeqLike.scala
+++ b/src/library/scala/collection/mutable/IndexedSeqLike.scala
@@ -45,7 +45,7 @@ trait IndexedSeqLike[A, +Repr] extends scala.collection.IndexedSeqLike[A, Repr]
/** Replaces element at given index with a new value.
*
* @param n the index of the element to replace.
- * @param lem the new value.
+ * @param elem the new value.
* @throws IndexOutofBoundsException if the index is not valid.
*/
def update(idx: Int, elem: A)
diff --git a/src/library/scala/collection/mutable/LinkedHashSet.scala b/src/library/scala/collection/mutable/LinkedHashSet.scala
index 7ecb71e23b..e91b03048d 100644
--- a/src/library/scala/collection/mutable/LinkedHashSet.scala
+++ b/src/library/scala/collection/mutable/LinkedHashSet.scala
@@ -87,7 +87,7 @@ class LinkedHashSet[A] extends Set[A]
* @define Coll LinkedHashSet
* @define coll linked hash set
*/
-object LinkedHashSet extends SetFactory[LinkedHashSet] {
+object LinkedHashSet extends MutableSetFactory[LinkedHashSet] {
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, LinkedHashSet[A]] = setCanBuildFrom[A]
override def empty[A]: LinkedHashSet[A] = new LinkedHashSet[A]
}
diff --git a/src/library/scala/collection/mutable/MapLike.scala b/src/library/scala/collection/mutable/MapLike.scala
index 676a325c9b..f9c0f7232c 100644
--- a/src/library/scala/collection/mutable/MapLike.scala
+++ b/src/library/scala/collection/mutable/MapLike.scala
@@ -191,9 +191,10 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]]
*
* @param p The test predicate
*/
- @deprecated("cannot be type inferred because of retain in Iterable.")
def retain(p: (A, B) => Boolean): this.type = {
- for ((k, v) <- this) if (!p(k, v)) -=(k)
+ for ((k, v) <- this ; if !p(k, v))
+ this -= k
+
this
}
diff --git a/src/library/scala/collection/mutable/Set.scala b/src/library/scala/collection/mutable/Set.scala
index 2e7f1cbc6b..bebf66157a 100644
--- a/src/library/scala/collection/mutable/Set.scala
+++ b/src/library/scala/collection/mutable/Set.scala
@@ -32,7 +32,7 @@ trait Set[A] extends Iterable[A]
* @define coll mutable set
* @define Coll mutable.Set
*/
-object Set extends SetFactory[Set] {
+object Set extends MutableSetFactory[Set] {
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Set[A]] = setCanBuildFrom[A]
override def empty[A]: Set[A] = HashSet.empty[A]
}
diff --git a/src/library/scala/collection/mutable/StringBuilder.scala b/src/library/scala/collection/mutable/StringBuilder.scala
index 40e7e991ee..f43acdc796 100644
--- a/src/library/scala/collection/mutable/StringBuilder.scala
+++ b/src/library/scala/collection/mutable/StringBuilder.scala
@@ -15,14 +15,17 @@ package mutable
import generic._
import compat.Platform.arraycopy
import scala.reflect.Manifest
+import annotation.migration
+import StringBuilder._
-/** A builder for mutable sequence of characters. This class provides an API compatible
- * with <a class="java/lang/StringBuilder" href="" target="_top">`java.lang.StringBuilder`</a>.
+/** A builder for mutable sequence of characters. This class provides an API
+ * mostly compatible with java.lang.StringBuilder, except where there are conflicts
+ * with the Scala collections API (such as the `reverse` method.)
*
* @author Stephane Micheloud
* @author Martin Odersky
* @version 2.8
- * @since 2.8
+ * @since 2.7
*/
@serializable
@SerialVersionUID(0 - 8525408645367278351L)
@@ -70,71 +73,50 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
*/
def clear(): Unit = setLength(0)
- /** Sets the length of the character sequence.
+ /** Sets the length of the character sequence. If the current sequence
+ * is shorter than the given length, it is padded with nulls; if it is
+ * longer, it is truncated.
*
- * @param newLength the new length
- * @throws IndexOutOfBoundsException if the <code>n</code> argument is negative.
+ * @param len the new length
+ * @throws IndexOutOfBoundsException if the argument is negative.
*/
- def setLength(n: Int) {
- require(n >= 0, n)
- while (count < n) append('\0')
- count = n
+ def setLength(len: Int) {
+ require(len >= 0, len)
+ while (count < len) append('\0')
+ count = len
}
- /** Returns the current capacity. The capacity is the amount of storage
- * available for newly inserted characters, beyond which an allocation
- * will occur.
+ /** Returns the current capacity, which is the size of the underlying array.
+ * A new array will be allocated if the current capacity is exceeded.
*
- * @return the current capacity
+ * @return the capacity
*/
def capacity: Int = array.length
- /** Same as <code>ensureCapacity</code>. */
- @deprecated("use `ensureCapacity' instead. An assignment is misleading because\n"+
+ @deprecated("Use `ensureCapacity' instead. An assignment is misleading because\n"+
"it can never decrease the capacity.")
def capacity_=(n: Int) { ensureCapacity(n) }
- /** <p>
- * Ensures that the capacity is at least equal to the specified minimum.
- * If the current capacity is less than the argument, then a new internal
- * array is allocated with greater capacity. The new capacity is the larger of:
- * </p>
- * <ul>
- * <li>The <code>n</code> argument.
- * <li>Twice the old capacity, plus <code>2</code>.
- * </ul>
- * <p>
- * If the <code>n</code> argument is non-positive, this
- * method takes no action and simply returns.
- * </p>
- *
- * @param n the minimum desired capacity.
- */
- def ensureCapacity(n: Int) {
- if (n > array.length) {
- var newsize = (array.length * 2) max 1
- while (n > newsize)
- newsize = newsize * 2
- val newar = new Array[Char](newsize)
- arraycopy(array, 0, newar, 0, count)
- array = newar
+ /** Ensure that the capacity is at least the given argument.
+ * If the argument is greater than the current capacity, new
+ * storage will be allocated with size equal to the given
+ * argument or to (2 * capacity + 2), whichever is larger.
+ *
+ * @param newCapacity the minimum desired capacity.
+ */
+ def ensureCapacity(newCapacity: Int): Unit =
+ if (newCapacity > array.length) {
+ val newSize = (array.length * 2 + 2) max newCapacity
+ val newArray = new Array[Char](newSize)
+ arraycopy(array, 0, newArray, 0, count)
+ array = newArray
}
- }
- /** <p>
- * Returns the <code>Char</code> value in this sequence at the specified index.
- * The first <code>Char</code> value is at index <code>0</code>, the next at index
- * <code>1</code>, and so on, as in array indexing.
- * </p>
- * <p>
- * The index argument must be greater than or equal to
- * <code>0</code>, and less than the length of this sequence.
- * </p>
- *
- * @param index the index of the desired <code>Char</code> value.
- * @return the <code>Char</code> value at the specified index.
- * @throws IndexOutOfBoundsException if <code>index</code> is
- * negative or greater than or equal to <code>length()</code>.
+ /** Returns the Char at the specified index, counting from 0 as in Arrays.
+ *
+ * @param index the index to look up
+ * @return the Char at the given index.
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
*/
def charAt(index: Int): Char = {
if (index < 0 || index >= count)
@@ -142,18 +124,16 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
array(index)
}
- /** Same as <code>charAt</code>. */
+ /** Equivalent to charAt.
+ */
def apply(i: Int): Char = charAt(i)
- /** <p>
- * Removes the <code>Char</code> at the specified position in this
- * sequence. This sequence is shortened by one <code>Char</code>.
- * </p>
+ /** Removes the Char at the specified index. The sequence is
+ * shortened by one.
*
- * @param index Index of <code>Char</code> to remove
- * @return This object.
- * @throws StringIndexOutOfBoundsException if the <code>index</code>
- * is negative or greater than or equal to <code>length()</code>.
+ * @param index The index to remove.
+ * @return This StringBuilder.
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
*/
def deleteCharAt(index: Int): StringBuilder = {
if (index < 0 || index >= count)
@@ -163,21 +143,11 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
this
}
- /** <p>
- * The character at the specified index is set to <code>ch</code>. This
- * sequence is altered to represent a new character sequence that is
- * identical to the old character sequence, except that it contains the
- * character <code>ch</code> at position <code>index</code>.
- * </p>
- * <p>
- * The index argument must be greater than or equal to
- * <code>0</code>, and less than the length of this sequence.
- * </p>
- *
- * @param index the index of the character to modify.
- * @param ch the new character.
- * @throws IndexOutOfBoundsException if <code>index</code> is
- * negative or greater than or equal to <code>length()</code>.
+ /** Update the sequence at the given index to hold the specified Char.
+ *
+ * @param index the index to modify.
+ * @param ch the new Char.
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
*/
def setCharAt(index: Int, ch: Char) {
if (index < 0 || index >= count)
@@ -185,33 +155,32 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
array(index) = ch
}
- /** Same as <code>setCharAt</code>. */
+ /** Equivalent to setCharAt.
+ */
def update(i: Int, c: Char) { setCharAt(i, c) }
- /** Returns a new <code>String</code> that contains a subsequence of
- * characters currently contained in this character sequence. The
- * substring begins at the specified index and extends to the end of
- * this sequence.
+ /** Returns a new String made up of a subsequence of this sequence,
+ * beginning at the given index and extending to the end of the sequence.
*
- * @param start The beginning index, inclusive.
- * @return The new string.
- * @throws StringIndexOutOfBoundsException if <code>start</code> is
- * less than zero, or greater than the length of this object.
+ * target.substring(start) is equivalent to target.drop(start)
+ *
+ * @param start The starting index, inclusive.
+ * @return The new String.
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
*/
- def substring(start: Int): String = substring(start, count)
+ def substring(start: Int): String = substring(start, length)
- /** Returns a new <code>String</code> that contains a subsequence of
- * characters currently contained in this sequence. The
- * substring begins at the specified <code>start</code> and
- * extends to the character at index <code>end - 1</code>.
+ /** Returns a new String made up of a subsequence of this sequence,
+ * beginning at the start index (inclusive) and extending to the
+ * end index (exclusive).
+ *
+ * target.substring(start, end) is equivalent to target.slice(start, end).mkString
*
* @param start The beginning index, inclusive.
* @param end The ending index, exclusive.
- * @return The new string.
- * @throws StringIndexOutOfBoundsException if <code>start</code>
- * or <code>end</code> are negative or greater than
- * <code>length()</code>, or <code>start</code> is
- * greater than <code>end</code>.
+ * @return The new String.
+ * @throws StringIndexOutOfBoundsException If either index is out of bounds,
+ * or if start > end.
*/
def substring(start: Int, end: Int): String = {
if (start < 0)
@@ -225,36 +194,29 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
def subSequence(start: Int, end: Int): java.lang.CharSequence = substring(start, end)
- /* Appends the string representation of the <code>Any</code> argument.
+ /** Appends the given Char to the end of the sequence.
*/
def +=(x: Char): this.type = { append(x); this }
+ /** !!! This should create a new sequence.
+ */
def +(x: Char): this.type = { +=(x); this }
-
- /** <p>
- * Appends the string representation of the <code>Any</code>
- * argument.
- * </p>
- * <p>
- * The argument is converted to a string as if by the method
- * <code>String.valueOf</code>, and the characters of that
- * string are then appended to this sequence.
- * </p>
+ /** Appends the string representation of the given argument,
+ * which is converted to a String with String.valueOf.
*
* @param x an <code>Any</code> object.
- * @return a reference to this object.
+ * @return this StringBuilder.
*/
- def append(x: Any): StringBuilder =
- append(String.valueOf(x))
+ def append(x: Any): StringBuilder = append(String.valueOf(x))
- /** Appends the specified string to this character sequence.
+ /** Appends the given String to this sequence.
*
- * @param s a string.
- * @return a reference to this object.
+ * @param s a String.
+ * @return this StringBuilder.
*/
def append(s: String): StringBuilder = {
- val str = if (s == null) "null" else s
+ val str = onull(s)
val len = str.length
ensureCapacity(count + len)
str.getChars(0, len, array, count)
@@ -278,92 +240,48 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
this
}
- /** <p>
- * Appends the string representation of the <code>Char</code> sequence
- * argument to this sequence.
- * </p>
- * <p>
- * The characters of the sequence argument are appended, in order,
- * to the contents of this sequence. The length of this sequence
- * increases by the length of the argument.
- * </p>
+ /** Appends all the Chars in the given Seq[Char] to this sequence.
*
- * @param x the characters to be appended.
- * @return a reference to this object.
+ * @param xs the characters to be appended.
+ * @return this StringBuilder.
*/
- def appendAll(x: Seq[Char]): StringBuilder =
- appendAll(x.toArray, 0, x.length)
+ def appendAll(xs: Seq[Char]): StringBuilder = appendAll(xs.toArray, 0, xs.length)
- @deprecated("use appendAll instead. This method is deprecated because of the\n"+
- "possible confusion with `append(Any)'.")
- def append(x: Seq[Char]): StringBuilder =
- appendAll(x)
-
- /** <p>
- * Appends the string representation of the <code>Char</code> array
- * argument to this sequence.
- * </p>
- * <p>
- * The characters of the array argument are appended, in order, to
- * the contents of this sequence. The length of this sequence
- * increases by the length of the argument.
- * </p>
+ /** Appends all the Chars in the given Array[Char] to this sequence.
*
- * @param x the characters to be appended.
- * @return a reference to this object.
+ * @param xs the characters to be appended.
+ * @return a reference to this object.
*/
- def appendAll(x: Array[Char]): StringBuilder =
- appendAll(x, 0, x.length)
+ def appendAll(xs: Array[Char]): StringBuilder = appendAll(xs, 0, xs.length)
- @deprecated("use appendAll instead. This method is deprecated because\n"+
- "of the possible confusion with `append(Any)'.")
- def append(x: Array[Char]): StringBuilder =
- appendAll(x)
-
- /** <p>
- * Appends the string representation of a subarray of the
- * <code>char</code> array argument to this sequence.
- * </p>
- * <p>
- * Characters of the <code>Char</code> array <code>x</code>, starting at
- * index <code>offset</code>, are appended, in order, to the contents
- * of this sequence. The length of this sequence increases
- * by the value of <code>len</code>.
- * </p>
- *
- * @param x the characters to be appended.
- * @param offset the index of the first <code>Char</code> to append.
- * @param len the number of <code>Char</code>s to append.
- * @return a reference to this object.
- */
- def appendAll(x: Array[Char], offset: Int, len: Int): StringBuilder = {
+ /** Appends a portion of the given Array[Char] to this sequence.
+ *
+ * @param xs the Array containing Chars to be appended.
+ * @param offset the index of the first Char to append.
+ * @param len the numbers of Chars to append.
+ * @return this StringBuilder.
+ */
+ def appendAll(xs: Array[Char], offset: Int, len: Int): StringBuilder = {
ensureCapacity(count + len)
- arraycopy(x, offset, array, count, len)
+ arraycopy(xs, offset, array, count, len)
count += len
this
}
- @deprecated("use appendAll instead. This method is deprecated because\n"+
- "of the possible confusion with `append(Any, Int, Int)'.")
- def append(x: Array[Char], offset: Int, len: Int): StringBuilder =
- appendAll(x, offset, len)
-
- /** <p>
- * Appends the string representation of the <code>Boolean</code>
- * argument to the sequence.
- * </p>
- * <p>
- * The argument is converted to a string as if by the method
- * <code>String.valueOf</code>, and the characters of that
- * string are then appended to this sequence.
- * </p>
- *
- * @param x a <code>Boolean</code>.
- * @return a reference to this object.
+ /** Append the String representation of the given primitive type
+ * to this sequence. The argument is converted to a String with
+ * String.valueOf.
+ *
+ * @param x a primitive value
+ * @return This StringBuilder.
*/
def append(x: Boolean): StringBuilder = append(String.valueOf(x))
def append(x: Byte): StringBuilder = append(String.valueOf(x))
-
+ def append(x: Short): StringBuilder = append(String.valueOf(x))
+ def append(x: Int): StringBuilder = append(String.valueOf(x))
+ def append(x: Long): StringBuilder = append(String.valueOf(x))
+ def append(x: Float): StringBuilder = append(String.valueOf(x))
+ def append(x: Double): StringBuilder = append(String.valueOf(x))
def append(x: Char): StringBuilder = {
ensureCapacity(count + 1)
array(count) = x
@@ -371,33 +289,14 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
this
}
- def append(x: Short): StringBuilder =
- append(String.valueOf(x))
-
- def append(x: Int): StringBuilder =
- append(String.valueOf(x))
-
- def append(x: Long): StringBuilder =
- append(String.valueOf(x))
-
- def append(x: Float): StringBuilder =
- append(String.valueOf(x))
-
- def append(x: Double): StringBuilder =
- append(String.valueOf(x))
-
- /** Removes the characters in a substring of this sequence.
- * The substring begins at the specified <code>start</code> and extends to
- * the character at index <code>end - 1</code> or to the end of the
- * sequence if no such character exists. If
- * <code>start</code> is equal to <code>end</code>, no changes are made.
+ /** Remove a subsequence of Chars from this sequence, starting at the
+ * given start index (inclusive) and extending to the end index (exclusive)
+ * or to the end of the String, whichever comes first.
*
* @param start The beginning index, inclusive.
* @param end The ending index, exclusive.
- * @return This object.
- * @throws StringIndexOutOfBoundsException if <code>start</code>
- * is negative, greater than <code>length()</code>, or
- * greater than <code>end</code>.
+ * @return This StringBuilder.
+ * @throws StringIndexOutOfBoundsException if start < 0 || start > end
*/
def delete(start: Int, end: Int): StringBuilder = {
if (start < 0 || start > end)
@@ -411,20 +310,14 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
this
}
- /** Replaces the characters in a substring of this sequence
- * with characters in the specified <code>String</code>. The substring
- * begins at the specified <code>start</code> and extends to the character
- * at index <code>end - 1</code> or to the end of the sequence if no such
- * character exists. First the characters in the substring are removed and
- * then the specified <code>String</code> is inserted at <code>start</code>.
+ /** Replaces a subsequence of Chars with the given String. The semantics
+ * are as in delete, with the String argument then inserted at index 'start'.
*
* @param start The beginning index, inclusive.
* @param end The ending index, exclusive.
- * @param str String that will replace previous contents.
- * @return This object.
- * @throws StringIndexOutOfBoundsException if <code>start</code>
- * is negative, greater than <code>length()</code>, or
- * greater than <code>end</code>.
+ * @param str The String to be inserted at the start index.
+ * @return This StringBuilder.
+ * @throws StringIndexOutOfBoundsException if start < 0, start > length, or start > end
*/
def replace(start: Int, end: Int, str: String) {
if (start < 0 || start > count || start > end)
@@ -441,25 +334,17 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
this
}
- /** Inserts the string representation of a subarray of the <code>str</code>
- * array argument into this sequence. The subarray begins at the specified
- * <code>offset</code> and extends <code>len</code> <code>char</code>s.
- * The characters of the subarray are inserted into this sequence at
- * the position indicated by <code>index</code>. The length of this
- * sequence increases by <code>len</code> <code>Char</code>s.
- *
- * @param index position at which to insert subarray.
- * @param str a <code>Char</code> array.
- * @param offset the index of the first <code>char</code> in subarray to
- * be inserted.
- * @param len the number of <code>Char</code>s in the subarray to
- * be inserted.
- * @return This object
- * @throws StringIndexOutOfBoundsException if <code>index</code>
- * is negative or greater than <code>length()</code>, or
- * <code>offset</code> or <code>len</code> are negative, or
- * <code>(offset+len)</code> is greater than
- * <code>str.length</code>.
+ /** Inserts a subarray of the given Array[Char] at the given index
+ * of this sequence.
+ *
+ * @param index index at which to insert the subarray.
+ * @param str the Array from which Chars will be taken.
+ * @param offset the index of the first Char to insert.
+ * @param len the number of Chars from 'str' to insert.
+ * @return This StringBuilder.
+ *
+ * @throws StringIndexOutOfBoundsException if index < 0, index > length,
+ * offset < 0, len < 0, or (offset + len) > str.length.
*/
def insertAll(index: Int, str: Array[Char], offset: Int, len: Int): StringBuilder = {
if (index < 0 || index > count)
@@ -475,368 +360,172 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
this
}
- @deprecated("use insertAll instead. This method is deprecated because of the\n"+
- "possible confusion with `insert(Int, Any, Int, Int)'.")
- def insert(index: Int, str: Array[Char], offset: Int, len: Int): StringBuilder =
- insertAll(index, str, offset, len)
-
- /** <p>
- * Inserts the string representation of the <code>Any</code>
- * argument into this character sequence.
- * </p>
- * <p>
- * The second argument is converted to a string as if by the method
- * <code>String.valueOf</code>, and the characters of that
- * string are then inserted into this sequence at the indicated
- * offset.
- * </p>
- * <p>
- * The offset argument must be greater than or equal to
- * <code>0</code>, and less than or equal to the length of this
- * sequence.
- * </p>
- *
- * @param offset the offset.
- * @param x an <code>Any</code> value.
- * @return a reference to this object.
- * @throws StringIndexOutOfBoundsException if the offset is invalid.
- */
- def insert(at: Int, x: Any): StringBuilder =
- insert(at, String.valueOf(x))
-
- /** Inserts the string into this character sequence.
- *
- * @param at the offset position.
- * @param x a string.
- * @return a reference to this object.
- * @throws StringIndexOutOfBoundsException if the offset is invalid.
+ /** Inserts the String representation (via String.valueOf) of the given
+ * argument into this sequence at the given index.
+ *
+ * @param index the index at which to insert.
+ * @param x a value.
+ * @return this StringBuilder.
+ * @throws StringIndexOutOfBoundsException if the index is out of bounds.
*/
- def insert(at: Int, x: String): StringBuilder = {
- if (at < 0 || at > count)
- throw new StringIndexOutOfBoundsException(at)
- val str = if (x == null) "null" else x
- val len = str.length
- ensureCapacity(count + len)
- arraycopy(array, at, array, at + len, count - at)
- str.getChars(0, len, array, at)
- count += len
- this
- }
+ def insert(index: Int, x: Any): StringBuilder = insert(index, String.valueOf(x))
- /** Inserts the string representation of the <code>Char</code> sequence
- * argument into this sequence.
+ /** Inserts the String into this character sequence.
*
- * @param at the offset position.
- * @param x a character sequence.
- * @return a reference to this object.
- * @throws StringIndexOutOfBoundsException if the offset is invalid.
+ * @param index the index at which to insert.
+ * @param x a String.
+ * @return this StringBuilder.
+ * @throws StringIndexOutOfBoundsException if the index is out of bounds.
*/
- def insertAll(at: Int, x: Seq[Char]): StringBuilder =
- insertAll(at, x.toArray)
+ def insert(index: Int, x: String): StringBuilder = insertAll(index, x.toArray)
- @deprecated("use insertAll instead. This method is deprecated because of\n"+
- "the possible confusion with `insert(Int, Any)'.")
- def insert(at: Int, x: Seq[Char]): StringBuilder =
- insertAll(at, x)
+ /** Inserts the given Seq[Char] into this sequence at the given index.
+ *
+ * @param index the index at which to insert.
+ * @param xs the Seq[Char].
+ * @return this StringBuilder.
+ * @throws StringIndexOutOfBoundsException if the index is out of bounds.
+ */
+ def insertAll(index: Int, xs: Seq[Char]): StringBuilder = insertAll(index, xs.toArray)
- /** Inserts the string representation of the <code>Char</code> array
- * argument into this sequence.
+ /** Inserts the given Array[Char] into this sequence at the given index.
*
- * @param at the offset position.
- * @param x a character array.
- * @return a reference to this object.
- * @throws StringIndexOutOfBoundsException if the offset is invalid.
+ * @param index the index at which to insert.
+ * @param xs the Array[Char].
+ * @return this StringBuilder.
+ * @throws StringIndexOutOfBoundsException if the index is out of bounds.
*/
- def insertAll(at: Int, x: Array[Char]): StringBuilder = {
- if (at < 0 || at > count)
- throw new StringIndexOutOfBoundsException(at)
- val len = x.length
+ def insertAll(index: Int, xs: Array[Char]): StringBuilder = {
+ if (index < 0 || index > count)
+ throw new StringIndexOutOfBoundsException(index)
+ val len = xs.length
ensureCapacity(count + len)
- arraycopy(array, at, array, at + len, count - at)
- arraycopy(x, 0, array, at, len)
+ arraycopy(array, index, array, index + len, count - index)
+ arraycopy(xs, 0, array, index, len)
count += len
this
}
+ /** Calls String.valueOf on the given primitive value, and inserts the
+ * String at the given index.
+ *
+ * @param index the offset position.
+ * @param x a primitive value.
+ * @return this StringBuilder.
+ */
+ def insert(index: Int, x: Boolean): StringBuilder = insert(index, String.valueOf(x))
+ def insert(index: Int, x: Byte): StringBuilder = insert(index, String.valueOf(x))
+ def insert(index: Int, x: Short): StringBuilder = insert(index, String.valueOf(x))
+ def insert(index: Int, x: Int): StringBuilder = insert(index, String.valueOf(x))
+ def insert(index: Int, x: Long): StringBuilder = insert(index, String.valueOf(x))
+ def insert(index: Int, x: Float): StringBuilder = insert(index, String.valueOf(x))
+ def insert(index: Int, x: Double): StringBuilder = insert(index, String.valueOf(x))
+ def insert(index: Int, x: Char): StringBuilder = {
+ if (index < 0 || index > count)
+ throw new StringIndexOutOfBoundsException(index)
+ ensureCapacity(count + 1)
+ arraycopy(array, index, array, index + 1, count - index)
+ array(index) = x
+ count += 1
+ this
+ }
+
+ @deprecated("Use appendAll instead. This method is deprecated because of the\n"+
+ "possible confusion with `append(Any)'.")
+ def append(x: Seq[Char]): StringBuilder = appendAll(x)
+
+ @deprecated("use appendAll instead. This method is deprecated because\n"+
+ "of the possible confusion with `append(Any)'.")
+ def append(x: Array[Char]): StringBuilder = appendAll(x)
+
+ @deprecated("use appendAll instead. This method is deprecated because\n"+
+ "of the possible confusion with `append(Any, Int, Int)'.")
+ def append(x: Array[Char], offset: Int, len: Int): StringBuilder = appendAll(x, offset, len)
+
+ @deprecated("use insertAll instead. This method is deprecated because of the\n"+
+ "possible confusion with `insert(Int, Any, Int, Int)'.")
+ def insert(index: Int, str: Array[Char], offset: Int, len: Int): StringBuilder =
+ insertAll(index, str, offset, len)
+
+ @deprecated("use insertAll instead. This method is deprecated because of\n"+
+ "the possible confusion with `insert(Int, Any)'.")
+ def insert(at: Int, x: Seq[Char]): StringBuilder = insertAll(at, x)
+
@deprecated("use insertAll instead. This method is deprecated because of\n"+
"the possible confusion with `insert(Int, Any)'.")
def insert(at: Int, x: Array[Char]): StringBuilder =
insertAll(at, x)
- /** <p>
- * Inserts the string representation of the <code>Boolean</code> argument
- * into this sequence.
- * </p>
- * <p>
- * The offset argument must be greater than or equal to 0, and less than
- * or equal to the length of this sequence.
- * </p>
- *
- * @param at the offset position.
- * @param x a <code>Boolean</code> value.
- * @return a reference to this object.
- */
- def insert(at: Int, x: Boolean): StringBuilder =
- insert(at, String.valueOf(x))
-
- /** <p>
- * Inserts the string representation of the <code>Byte</code> argument
- * into this sequence.
- * </p>
- * <p>
- * The offset argument must be greater than or equal to 0, and less than
- * or equal to the length of this sequence.
- * </p>
+ /** Finds the index of the first occurrence of the specified substring.
*
- * @param at the offset position.
- * @param x a <code>Byte</code> value.
- * @return a reference to this object.
+ * @param str the target string to search for
+ * @return the first applicable index where target occurs, or -1 if not found.
*/
- def insert(at: Int, x: Byte): StringBuilder =
- insert(at, String.valueOf(x))
+ def indexOf(str: String): Int = indexOf(str, 0)
- /** <p>
- * Inserts the string representation of the <code>Char</code> argument
- * into this sequence.
- * </p>
- * <p>
- * The offset argument must be greater than or equal to 0, and less than
- * or equal to the length of this sequence.
- * </p>
+ /** Finds the index of the first occurrence of the specified substring.
*
- * @param at the offset position.
- * @param x a <code>Char</code> value.
- * @return a reference to this object.
- */
- def insert(at: Int, x: Char): StringBuilder = {
- if (at < 0 || at > count)
- throw new StringIndexOutOfBoundsException(at)
- ensureCapacity(count + 1)
- arraycopy(array, at, array, at + 1, count - at)
- array(at) = x
- count += 1
- this
- }
-
- /** <p>
- * Inserts the string representation of the <code>Short</code> argument
- * into this sequence.
- * </p>
- * <p>
- * The offset argument must be greater than or equal to 0, and less than
- * or equal to the length of this sequence.
- * </p>
- *
- * @param at the offset position.
- * @param x a <code>Short</code> value.
- * @return a reference to this object.
+ * @param str the target string to search for
+ * @param fromIndex the smallest index in the source string to consider
+ * @return the first applicable index where target occurs, or -1 if not found.
*/
- def insert(at: Int, x: Short): StringBuilder =
- insert(at, String.valueOf(x))
+ def indexOf(str: String, fromIndex: Int): Int = indexOfSlice(str.toIndexedSeq, fromIndex)
- /** <p>
- * Inserts the string representation of the <code>Int</code> argument
- * into this sequence.
- * </p>
- * <p>
- * The offset argument must be greater than or equal to 0, and less than
- * or equal to the length of this sequence.
- * </p>
+ /** Finds the index of the last occurrence of the specified substring.
*
- * @param at the offset position.
- * @param x a <code>Int</code> value.
- * @return a reference to this object.
+ * @param str the target string to search for
+ * @return the last applicable index where target occurs, or -1 if not found.
*/
- def insert(at: Int, x: Int): StringBuilder =
- insert(at, String.valueOf(x))
+ def lastIndexOf(str: String): Int = lastIndexOf(str, count)
- /** <p>
- * Inserts the string representation of the <code>Long</code> argument
- * into this sequence.
- * </p>
- * <p>
- * The offset argument must be greater than or equal to 0, and less than
- * or equal to the length of this sequence.
- * </p>
+ /** Finds the index of the last occurrence of the specified substring.
*
- * @param at the offset position.
- * @param x a <code>Long</code> value.
- * @return a reference to this object.
+ * @param str the target string to search for
+ * @param fromIndex the smallest index in the source string to consider
+ * @return the last applicable index where target occurs, or -1 if not found.
*/
- def insert(at: Int, x: Long): StringBuilder =
- insert(at, String.valueOf(x))
+ def lastIndexOf(str: String, fromIndex: Int): Int = lastIndexOfSlice(str.toIndexedSeq, fromIndex)
- /** <p>
- * Inserts the string representation of the <code>Float</code> argument
- * into this sequence.
- * </p>
- * <p>
- * The offset argument must be greater than or equal to 0, and less than
- * or equal to the length of this sequence.
- * </p>
+ /** Creates a new StringBuilder with the reversed contents of this one.
+ * If surrogate pairs are present, they are treated as indivisible units: each
+ * pair will appear in the same order in the updated sequence.
*
- * @param at the offset position.
- * @param x a <code>Float</code> value.
- * @return a reference to this object.
+ * @return the reversed StringBuilder
*/
- def insert(at: Int, x: Float): StringBuilder =
- insert(at, String.valueOf(x))
+ @migration(2, 8, "Since 2.8 reverse returns a new instance. Use 'reverseContents' to update in place.")
+ override def reverse: StringBuilder = new StringBuilder(this.toString).reverseContents()
- /** <p>
- * Inserts the string representation of the <code>Double</code> argument
- * into this sequence.
- * </p>
- * <p>
- * The offset argument must be greater than or equal to 0, and less than
- * or equal to the length of this sequence.
- * </p>
+ /** Like reverse, but destructively updates the target StringBuilder.
*
- * @param at the offset position.
- * @param x a <code>Double</code> value.
- * @return a reference to this object.
- */
- def insert(at: Int, x: Double): StringBuilder =
- insert(at, String.valueOf(x))
-
- /** <p>
- * Returns the index within this string of the first occurrence of the
- * specified substring. The integer returned is the smallest value
- * <i>k</i> such that:
- * </p>
- * <blockquote><pre>
- * this.toString().startsWith(str, <i>k</i>)</pre>
- * </blockquote>
- * <p>
- * is <code>true</code>.
- * </p>
- *
- * @param str any string.
- * @return if the string argument occurs as a substring within this
- * object, then the index of the first character of the first
- * such substring is returned; if it does not occur as a
- * substring, <code>-1</code> is returned.
- * @throws NullPointerException if <code>str</code> is <code>null</code>.
+ * @return the reversed StringBuilder (same as the target StringBuilder)
*/
- def indexOf(str: String): Int = indexOf(str, 0)
+ def reverseContents(): StringBuilder = {
+ // record of indices of pairs which need to be swapped
+ val surrogates = new ListBuffer[(Int, Int)]
+ val half = count / 2
- /** <p>
- * Returns the index within this string of the first occurrence of the
- * specified substring, starting at the specified index. The integer
- * returned is the smallest value <code>k</code> for which:
- * </p><pre>
- * k >= math.min(fromIndex, str.length()) &&
- * this.toString().startsWith(str, k)</pre>
- * <p>
- * If no such value of <code>k</code> exists, then <code>-1</code>
- * is returned.
- * </p>
- *
- * @param str the substring for which to search.
- * @param fromIndex the index from which to start the search.
- * @return the index within this string of the first occurrence
- * of the specified substring, starting at the specified index.
- */
- def indexOf(str: String, fromIndex: Int): Int = indexOfSlice(str.toIndexedSeq, fromIndex)
-
- /** <p>
- * Returns the index within this string of the rightmost occurrence
- * of the specified substring. The rightmost empty string "" is
- * considered to occur at the index value <code>this.length()</code>.
- * The returned index is the largest value <i>k</i> such that
- * </p>
- * <blockquote><pre>
- * this.toString().startsWith(str, k)</pre>
- * </blockquote>
- * <p>
- * is true.
- * </p>
- *
- * @param str the substring to search for.
- * @return if the string argument occurs one or more times as a substring
- * within this object, then the index of the first character of
- * the last such substring is returned. If it does not occur as
- * a substring, <code>-1</code> is returned.
- * @throws NullPointerException if <code>str</code> is <code>null</code>.
- */
- def lastIndexOf(str: String): Int = lastIndexOf(str, count)
+ def mirror(x: Int) = count - 1 - x
+ def swap(i1: Int, i2: Int) {
+ val tmp = array(i2)
+ array(i2) = array(i1)
+ array(i1) = tmp
+ }
- /** <p>
- * Returns the index within this string of the last occurrence of the
- * specified substring. The integer returned is the largest value
- * <code>k</code> such that:
- * </p><pre>val
- * k <= math.min(fromIndex, str.length()) &&
- * this.toString().startsWith(str, k)</pre>
- * <p>
- * If no such value of <code>k</code> exists, then <code>-1</code>
- * is returned.
- * </p>
- *
- * @param str the substring to search for.
- * @param fromIndex the index to start the search from.
- * @return the index within this sequence of the last occurrence
- * of the specified substring.
- */
- def lastIndexOf(str: String, fromIndex: Int): Int = lastIndexOfSlice(str.toIndexedSeq, fromIndex)
+ for ((i, j) <- 0 until half zip (count - 1 to half by -1)) {
+ if (array(i).isSurrogate && array(i + 1).isSurrogate)
+ surrogates += ((j - 1, j))
+ if (array(j).isSurrogate && array(j - 1).isSurrogate)
+ surrogates += ((i, i + 1))
- /** <p>
- * Causes this character sequence to be replaced by the reverse of the
- * sequence. If there are any surrogate pairs included in the sequence,
- * these are treated as single characters for the reverse operation.
- * Thus, the order of the high-low surrogates is never reversed.
- * </p>
- * <p>
- * Let <i>n</i> be the character length of this character sequence
- * (not the length in <code>Char</code> values) just prior to
- * execution of the <code>reverse</code> method. Then the
- * character at index <i>k</i> in the new character sequence is
- * equal to the character at index <i>n-k-1</i> in the old
- * character sequence.
- * </p>
- *
- * @return a reference to this object.
- */
- override def reverse(): StringBuilder = {
- var hasSurrogate = false
- val n = count - 1
- var j = (n-1) >> 1
- while (j >= 0) {
- val temp = array(j)
- val temp2 = array(n - j)
- if (!hasSurrogate)
- hasSurrogate =
- (temp >= Character.MIN_HIGH_SURROGATE && temp <= Character.MAX_LOW_SURROGATE) ||
- (temp2 >= Character.MIN_HIGH_SURROGATE && temp2 <= Character.MAX_LOW_SURROGATE)
- array(j) = temp2
- array(n - j) = temp
- j -= 1
- }
- if (hasSurrogate) {
- // Reverse back all valid surrogate pairs
- var i = 0
- while (i < count - 1) {
- val c2 = array(i)
- if (Character.isLowSurrogate(c2)) {
- val c1 = array(i + 1)
- if (Character.isHighSurrogate(c1)) {
- array(i) = c1; i += 1
- array(i) = c2
- }
- }
- i += 1
- }
+ swap(i, j)
}
+ surrogates foreach (swap _).tupled
this
}
- /** Returns a string representing the data in this sequence.
- * A new <code>String</code> object is allocated and initialized to
- * contain the character sequence currently represented by this
- * object. This <code>String</code> is then returned. Subsequent
- * changes to this sequence do not affect the contents of the
- * <code>String</code>.
+ /** Returns a new String representing the data in this sequence.
*
- * @return a string representation of this sequence of characters.
+ * @return the current contents of this sequence as a String
*/
override def toString: String = new String(array, 0, count)
@@ -852,4 +541,7 @@ object StringBuilder
arraycopy(src, 0, dest, 0, src.length min newLength)
dest
}
+
+ // for mimicking java's propensity to make null into "null"
+ private def onull(s: String): String = if (s == null) "null" else s
}
diff --git a/src/library/scala/concurrent/TaskRunner.scala b/src/library/scala/concurrent/TaskRunner.scala
index 0853007a28..f7d3002b83 100644
--- a/src/library/scala/concurrent/TaskRunner.scala
+++ b/src/library/scala/concurrent/TaskRunner.scala
@@ -25,9 +25,4 @@ trait TaskRunner {
def shutdown(): Unit
- /** If expression computed successfully return it in <code>Right</code>,
- * otherwise return exception in <code>Left</code>.
- */
- protected def tryCatch[A](body: => A): Either[Exception, A] =
- ops tryCatchEx body
}
diff --git a/src/library/scala/concurrent/ThreadRunner.scala b/src/library/scala/concurrent/ThreadRunner.scala
index 13bf20ff2a..5cfc076699 100644
--- a/src/library/scala/concurrent/ThreadRunner.scala
+++ b/src/library/scala/concurrent/ThreadRunner.scala
@@ -25,6 +25,14 @@ class ThreadRunner extends FutureTaskRunner {
implicit def functionAsTask[S](fun: () => S): Task[S] = fun
implicit def futureAsFunction[S](x: Future[S]): () => S = x
+ /* If expression computed successfully return it in `Right`,
+ * otherwise return exception in `Left`.
+ */
+ private def tryCatch[A](body: => A): Either[Exception, A] =
+ try Right(body) catch {
+ case ex: Exception => Left(ex)
+ }
+
def execute[S](task: Task[S]) {
val runnable = new Runnable {
def run() { tryCatch(task()) }
@@ -38,7 +46,7 @@ class ThreadRunner extends FutureTaskRunner {
def run() { result set tryCatch(task()) }
}
(new Thread(runnable)).start()
- () => ops getOrThrow result.get
+ () => result.get.fold[S](throw _, identity _)
}
def managedBlock(blocker: ManagedBlocker) {
diff --git a/src/library/scala/concurrent/ops.scala b/src/library/scala/concurrent/ops.scala
index 6537a47258..49be1b882c 100644
--- a/src/library/scala/concurrent/ops.scala
+++ b/src/library/scala/concurrent/ops.scala
@@ -23,21 +23,13 @@ object ops
val defaultRunner: FutureTaskRunner = TaskRunners.threadRunner
/**
- * If expression computed successfully return it in <code>Right</code>,
- * otherwise return exception in <code>Left</code>.
+ * If expression computed successfully return it in `Right`,
+ * otherwise return exception in `Left`.
*/
- //TODO: make private
- def tryCatch[A](body: => A): Either[Throwable, A] =
+ private def tryCatch[A](body: => A): Either[Throwable, A] =
allCatch[A] either body
- //TODO: make private
- def tryCatchEx[A](body: => A): Either[Exception, A] =
- try Right(body) catch {
- case ex: Exception => Left(ex)
- }
-
- //TODO: make private
- def getOrThrow[T <: Throwable, A](x: Either[T, A]): A =
+ private def getOrThrow[T <: Throwable, A](x: Either[T, A]): A =
x.fold[A](throw _, identity _)
/** Evaluates an expression asynchronously.
diff --git a/src/library/scala/math/BigDecimal.scala b/src/library/scala/math/BigDecimal.scala
index c4cccd1f52..67604e8b78 100644
--- a/src/library/scala/math/BigDecimal.scala
+++ b/src/library/scala/math/BigDecimal.scala
@@ -19,24 +19,23 @@ import scala.collection.immutable.NumericRange
* @version 1.0
* @since 2.7
*/
-object BigDecimal
-{
- @serializable
- object RoundingMode extends Enumeration(java.math.RoundingMode.values map (_.toString) : _*) {
- type RoundingMode = Value
- val UP, DOWN, CEILING, FLOOR, HALF_UP, HALF_DOWN, HALF_EVEN, UNNECESSARY = Value
- }
-
+object BigDecimal {
private val minCached = -512
private val maxCached = 512
- val MinLong = BigDecimal(Long.MinValue)
- val MaxLong = BigDecimal(Long.MaxValue)
+ val defaultMathContext = MathContext.UNLIMITED
+
+ val MinLong = new BigDecimal(BigDec valueOf Long.MinValue, defaultMathContext)
+ val MaxLong = new BigDecimal(BigDec valueOf Long.MaxValue, defaultMathContext)
/** Cache ony for defaultMathContext using BigDecimals in a small range. */
private lazy val cache = new Array[BigDecimal](maxCached - minCached + 1)
- val defaultMathContext = MathContext.UNLIMITED
+ @serializable
+ object RoundingMode extends Enumeration(java.math.RoundingMode.values map (_.toString) : _*) {
+ type RoundingMode = Value
+ val UP, DOWN, CEILING, FLOOR, HALF_UP, HALF_DOWN, HALF_EVEN, UNNECESSARY = Value
+ }
/** Constructs a <code>BigDecimal</code> using the java BigDecimal static
* valueOf constructor.
diff --git a/src/library/scala/reflect/Manifest.scala b/src/library/scala/reflect/Manifest.scala
index b7cb86e1bd..d718011ff9 100644
--- a/src/library/scala/reflect/Manifest.scala
+++ b/src/library/scala/reflect/Manifest.scala
@@ -245,16 +245,15 @@ object Manifest {
override def toString = prefix.toString+"#"+name+argString
}
- /** Manifest for the abstract type `prefix # name'. `upperBound' is not
- * strictly necessary as it could be obtained by reflection. It was
- * added so that erasure can be calculated without reflection.
- * todo: remove after next bootstrap
+ /** Manifest for the unknown type `_ >: L <: U' in an existential.
*/
- def abstractType[T](prefix: Manifest[_], name: String, upperbound: ClassManifest[_], args: Manifest[_]*): Manifest[T] =
+ def wildcardType[T](lowerBound: Manifest[_], upperBound: Manifest[_]): Manifest[T] =
new (Manifest[T] @serializable) {
- def erasure = upperbound.erasure
- override val typeArguments = args.toList
- override def toString = prefix.toString+"#"+name+argString
+ def erasure = upperBound.erasure
+ override def toString =
+ "_" +
+ (if (lowerBound eq Nothing) "" else " >: "+lowerBound) +
+ (if (upperBound eq Nothing) "" else " <: "+upperBound)
}
/** Manifest for the intersection type `parents_0 with ... with parents_n'. */
diff --git a/src/library/scala/reflect/generic/Flags.scala b/src/library/scala/reflect/generic/Flags.scala
index f0f1f14ade..c8ef529bc1 100755
--- a/src/library/scala/reflect/generic/Flags.scala
+++ b/src/library/scala/reflect/generic/Flags.scala
@@ -53,9 +53,10 @@ class Flags {
final val ACCESSOR = 0x08000000 // a value or variable accessor (getter or setter)
final val SUPERACCESSOR = 0x10000000 // a super accessor
- final val PARAMACCESSOR = 0x20000000 // for value definitions: is an access method
- // for a final val parameter
- // for parameters: is a val parameter
+ final val PARAMACCESSOR = 0x20000000 // for field definitions generated for primary constructor
+ // parameters (no matter if it's a 'val' parameter or not)
+ // for parameters of a primary constructor ('val' or not)
+ // for the accessor methods generated for 'val' or 'var' parameters
final val MODULEVAR = 0x40000000 // for variables: is the variable caching a module value
final val SYNTHETICMETH = 0x40000000 // for methods: synthetic method, but without SYNTHETIC flag
final val MONOMORPHIC = 0x40000000 // for type symbols: does not have type parameters
diff --git a/src/library/scala/reflect/generic/Trees.scala b/src/library/scala/reflect/generic/Trees.scala
index df93d157e3..c880a335de 100755
--- a/src/library/scala/reflect/generic/Trees.scala
+++ b/src/library/scala/reflect/generic/Trees.scala
@@ -37,6 +37,7 @@ trait Trees { self: Universe =>
def isProtected = hasFlag(PROTECTED)
def isPublic = !isPrivate && !isProtected
def isSealed = hasFlag(SEALED )
+ def isSynthetic = hasFlag(SYNTHETIC)
def isTrait = hasFlag(TRAIT )
def isVariable = hasFlag(MUTABLE )
diff --git a/src/library/scala/runtime/RichChar.scala b/src/library/scala/runtime/RichChar.scala
index f5e2625fd8..1c95186558 100644
--- a/src/library/scala/runtime/RichChar.scala
+++ b/src/library/scala/runtime/RichChar.scala
@@ -48,6 +48,7 @@ final class RichChar(x: Char) extends Proxy with Ordered[Char] {
def isSpaceChar: Boolean = Character.isSpaceChar(x)
def isHighSurrogate: Boolean = Character.isHighSurrogate(x)
def isLowSurrogate: Boolean = Character.isLowSurrogate(x)
+ def isSurrogate: Boolean = isHighSurrogate || isLowSurrogate
def isUnicodeIdentifierStart: Boolean = Character.isUnicodeIdentifierStart(x)
def isUnicodeIdentifierPart: Boolean = Character.isUnicodeIdentifierPart(x)
def isIdentifierIgnorable: Boolean = Character.isIdentifierIgnorable(x)
diff --git a/src/library/scala/transient.scala b/src/library/scala/transient.scala
index d8b8ee4d86..aea7ba7b5f 100644
--- a/src/library/scala/transient.scala
+++ b/src/library/scala/transient.scala
@@ -11,4 +11,7 @@
package scala
+import annotation.target._
+
+@field
class transient extends StaticAnnotation
diff --git a/src/library/scala/util/parsing/combinator/RegexParsers.scala b/src/library/scala/util/parsing/combinator/RegexParsers.scala
index 89c5050431..fd8ee60db0 100644
--- a/src/library/scala/util/parsing/combinator/RegexParsers.scala
+++ b/src/library/scala/util/parsing/combinator/RegexParsers.scala
@@ -67,6 +67,25 @@ trait RegexParsers extends Parsers {
}
}
+ /** `positioned' decorates a parser's result with the start position of the input it consumed.
+ * If whitespace is being skipped, then it is skipped before the start position is recorded.
+ *
+ * @param p a `Parser' whose result conforms to `Positional'.
+ * @return A parser that has the same behaviour as `p', but which marks its result with the
+ * start position of the input it consumed after whitespace has been skipped, if it
+ * didn't already have a position.
+ */
+ override def positioned[T <: Positional](p: => Parser[T]): Parser[T] = {
+ val pp = super.positioned(p)
+ new Parser[T] {
+ def apply(in: Input) = {
+ val offset = in.offset
+ val start = handleWhiteSpace(in.source, offset)
+ pp(in.drop (start - offset))
+ }
+ }
+ }
+
override def phrase[T](p: Parser[T]): Parser[T] =
super.phrase(p <~ opt("""\z""".r))
diff --git a/src/library/scala/volatile.scala b/src/library/scala/volatile.scala
index dda0493bf9..005cd6628c 100644
--- a/src/library/scala/volatile.scala
+++ b/src/library/scala/volatile.scala
@@ -11,4 +11,7 @@
package scala
+import annotation.target._
+
+@field
class volatile extends StaticAnnotation
diff --git a/src/library/scala/xml/NodeSeq.scala b/src/library/scala/xml/NodeSeq.scala
index 3b56ba25e4..0cab5422b6 100644
--- a/src/library/scala/xml/NodeSeq.scala
+++ b/src/library/scala/xml/NodeSeq.scala
@@ -73,16 +73,18 @@ abstract class NodeSeq extends immutable.Seq[Node] with SeqLike[Node, NodeSeq] w
case _ => false
}
- /** Projection function. Similar to XPath, use <code>this \ "foo"</code>
- * to get a list of all elements of this sequence that are labelled with
- * <code>"foo"</code>. Use <code>\ "_"</code> as a wildcard. Use
- * <code>ns \ "@foo"</code> to get the unprefixed attribute "foo".
- * Use <code>ns \ "@{uri}foo"</code> to get the prefixed attribute
- * "pre:foo" whose prefix "pre" is resolved to the namespace "uri".
- * For attribute projections, the resulting NodeSeq attribute values are
- * wrapped in a Group.
- * There is no support for searching a prefixed attribute by
- * its literal prefix.
+ /** Projection function, which returns elements of `this` sequence based on the string `that`. Use:
+ * - `this \ "foo"` to get a list of all elements that are labelled with `"foo"`;
+ * - `\ "_"` to get a list of all elements (wildcard);
+ * - `ns \ "@foo"` to get the unprefixed attribute `"foo"`;
+ * - `ns \ "@{uri}foo"` to get the prefixed attribute `"pre:foo"` whose prefix `"pre"` is resolved to the
+ * namespace `"uri"`.
+ *
+ * For attribute projections, the resulting [[scala.xml.NodeSeq]] attribute values are wrapped in a
+ * [[scala.xml.Group]].
+ *
+ * There is no support for searching a prefixed attribute by its literal prefix.
+ *
* The document order is preserved.
*
* @param that ...
@@ -120,16 +122,19 @@ abstract class NodeSeq extends immutable.Seq[Node] with SeqLike[Node, NodeSeq] w
}
}
- /** projection function. Similar to XPath, use <code>this \\ 'foo</code>
- * to get a list of all elements of this sequence that are labelled with
- * <code>"foo"</code>. Use <code>\\ "_"</code> as a wildcard. Use
- * <code>ns \\ "@foo"</code> to get the unprefixed attribute "foo".
- * Use <code>ns \\ "@{uri}foo"</code> to get each prefixed attribute
- * "pre:foo" whose prefix "pre" is resolved to the namespace "uri".
- * For attribute projections, the resulting NodeSeq attribute values are
- * wrapped in a Group.
- * There is no support for searching a prefixed attribute by
- * its literal prefix.
+ /** Projection function, which returns elements of `this` sequence and of all its subsequences, based on
+ * the string `that`. Use:
+ * - `this \\ 'foo` to get a list of all elements that are labelled with `"foo"`;
+ * - `\\ "_"` to get a list of all elements (wildcard);
+ * - `ns \\ "@foo"` to get the unprefixed attribute `"foo"`;
+ * - `ns \\ "@{uri}foo"` to get each prefixed attribute `"pre:foo"` whose prefix `"pre"` is resolved to the
+ * namespace `"uri"`.
+ *
+ * For attribute projections, the resulting [[scala.xml.NodeSeq]] attribute values are wrapped in a
+ * [[scala.xml.Group]].
+ *
+ * There is no support for searching a prefixed attribute by its literal prefix.
+ *
* The document order is preserved.
*
* @param that ...
diff --git a/src/library/scala/xml/Utility.scala b/src/library/scala/xml/Utility.scala
index 48a23dc389..8637148489 100644
--- a/src/library/scala/xml/Utility.scala
+++ b/src/library/scala/xml/Utility.scala
@@ -194,22 +194,24 @@ object Utility extends AnyRef with parsing.TokenTests
minimizeTags: Boolean = false): StringBuilder =
{
x match {
- case c: Comment if !stripComments => c buildString sb
- case x: SpecialNode => x buildString sb
- case g: Group => for (c <- g.nodes) toXML(c, x.scope, sb) ; sb
+ case c: Comment => if (!stripComments) c buildString sb else sb
+ case x: SpecialNode => x buildString sb
+ case g: Group =>
+ g.nodes foreach {toXML(_, x.scope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags)}
+ sb
case _ =>
// print tag with namespace declarations
sb.append('<')
x.nameToString(sb)
if (x.attributes ne null) x.attributes.buildString(sb)
x.scope.buildString(sb, pscope)
- if (x.child.isEmpty && minimizeTags)
+ if (x.child.isEmpty && minimizeTags) {
// no children, so use short form: <xyz .../>
sb.append(" />")
- else {
+ } else {
// children, so use long form: <xyz ...>...</xyz>
sb.append('>')
- sequenceToXML(x.child, x.scope, sb, stripComments)
+ sequenceToXML(x.child, x.scope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags)
sb.append("</")
x.nameToString(sb)
sb.append('>')
@@ -221,20 +223,23 @@ object Utility extends AnyRef with parsing.TokenTests
children: Seq[Node],
pscope: NamespaceBinding = TopScope,
sb: StringBuilder = new StringBuilder,
- stripComments: Boolean = false): Unit =
+ stripComments: Boolean = false,
+ decodeEntities: Boolean = true,
+ preserveWhitespace: Boolean = false,
+ minimizeTags: Boolean = false): Unit =
{
if (children.isEmpty) return
else if (children forall isAtomAndNotText) { // add space
val it = children.iterator
val f = it.next
- toXML(f, pscope, sb)
+ toXML(f, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags)
while (it.hasNext) {
val x = it.next
sb.append(' ')
- toXML(x, pscope, sb)
+ toXML(x, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags)
}
}
- else children foreach { toXML(_, pscope, sb) }
+ else children foreach { toXML(_, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags) }
}
/**
diff --git a/src/library/scala/xml/Xhtml.scala b/src/library/scala/xml/Xhtml.scala
index 744fe260c2..162ea5696a 100644
--- a/src/library/scala/xml/Xhtml.scala
+++ b/src/library/scala/xml/Xhtml.scala
@@ -49,11 +49,11 @@ object Xhtml
(minimizableElements contains x.label)
x match {
- case c: Comment if !stripComments => c buildString sb
+ case c: Comment => if (!stripComments) c buildString sb
case er: EntityRef if decodeEntities => decode(er)
case x: SpecialNode => x buildString sb
case g: Group =>
- g.nodes foreach { toXhtml(_, x.scope, sb) }
+ g.nodes foreach { toXhtml(_, x.scope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags) }
case _ =>
sb.append('<')
@@ -64,7 +64,7 @@ object Xhtml
if (shortForm) sb.append(" />")
else {
sb.append('>')
- sequenceToXML(x.child, x.scope, sb)
+ sequenceToXML(x.child, x.scope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags)
sb.append("</")
x.nameToString(sb)
sb.append('>')
@@ -89,9 +89,9 @@ object Xhtml
val doSpaces = children forall isAtomAndNotText // interleave spaces
for (c <- children.take(children.length - 1)) {
- toXhtml(c, pscope, sb)
+ toXhtml(c, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags)
if (doSpaces) sb append ' '
}
- toXhtml(children.last, pscope, sb)
+ toXhtml(children.last, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags)
}
}
diff --git a/src/partest/scala/tools/partest/Actions.scala b/src/partest/scala/tools/partest/Actions.scala
index ce554959eb..5cbe64ce23 100644
--- a/src/partest/scala/tools/partest/Actions.scala
+++ b/src/partest/scala/tools/partest/Actions.scala
@@ -35,11 +35,11 @@ trait Actions {
val cmd = fromArgs(args)
if (isVerbose) {
- trace(execEnv.mkString("ENV(", "\n", "\n)"))
+ trace("runExec: " + execEnv.mkString("ENV(", "\n", "\n)"))
execCwd foreach (x => trace("CWD(" + x + ")"))
}
- trace(cmd)
+ trace("runExec: " + cmd)
isDryRun || execAndLog(cmd)
}
@@ -69,20 +69,19 @@ trait Actions {
trait ScriptableTest {
self: TestEntity =>
- // def customTestStep(line: String): TestStep
-
/** Translates a line from a .cmds file into a teststep.
*/
def customTestStep(line: String): TestStep = {
+ trace("customTestStep: " + line)
val (cmd, rest) = line span (x => !Character.isWhitespace(x))
- val args = toArgs(rest)
+ def qualify(name: String) = sourcesDir / name path
+ val args = toArgs(rest) map qualify
def fail: TestStep = (_: TestEntity) => error("Parse error: did not understand '%s'" format line)
val f: TestEntity => Boolean = cmd match {
case "scalac" => _ scalac args
case "javac" => _ javac args
case "scala" => _ runScala args
- case "diff" => if (args.size != 2) fail else _ => diffFiles(File(args(0)), File(args(1))) == ""
case _ => fail
}
f
@@ -109,6 +108,8 @@ trait Actions {
* to know exactly when and how two-pass compilation fails.
*/
def compile() = {
+ trace("compile: " + sourceFiles)
+
def compileJava() = javac(javaSources)
def compileScala() = scalac(scalaSources)
def compileAll() = scalac(allSources)
@@ -123,54 +124,82 @@ trait Actions {
self: TestEntity =>
def checkFile: File = withExtension("check").toFile
- def isCheckPresent = checkFile.isFile || {
- warnAndLog("A checkFile at '%s' is mandatory.\n" format checkFile.path)
- false
- }
+ def checkFileRequired =
+ returning(checkFile.isFile)(res => if (!res) warnAndLog("A checkFile at '%s' is mandatory.\n" format checkFile.path))
- def normalizePaths(s: String) = {
- /** This accomodates slash/backslash issues by noticing when a given
- * line was altered, which means it held a path, and only then converting any
- * backslashes to slashes. It's not foolproof but it's as close as we
- * can get in one line.
- */
- val s2 = s.replaceAll("""(?m)\Q%s\E""" format (sourcesDir + File.separator), "")
- if (s != s2) s2.replaceAll("""\\""", "/") else s2
- }
+ lazy val sourceFileNames = sourceFiles map (_.name)
+
+ /** Given the difficulty of verifying that any selective approach works
+ * everywhere, the algorithm now is to look for the name of any known
+ * source file for this test, and if seen, remove all the non-whitespace
+ * preceding it. (Paths with whitespace don't work anyway.) This should
+ * wipe out all slashes, backslashes, C:\, cygwin/windows differences,
+ * and whatever else makes a simple diff not simple.
+ *
+ * The log and check file are both transformed, which I don't think is
+ * correct -- only the log should be -- but doing it this way until I
+ * can clarify martin's comments in #3283.
+ */
+ def normalizePaths(s: String) =
+ sourceFileNames.foldLeft(s)((res, name) => res.replaceAll("""\S+\Q%s\E""" format name, name))
- /** The default cleanup normalizes paths relative to sourcesDir.
+ /** The default cleanup normalizes paths relative to sourcesDir,
+ * absorbs line terminator differences by going to lines and back,
+ * and trims leading or trailing whitespace.
*/
- def diffCleanup(f: File) = safeLines(f) map normalizePaths mkString ("", "\n", "\n")
+ def diffCleanup(f: File) = safeLines(f) map normalizePaths mkString "\n" trim
+
+ /** diffFiles requires actual Files as arguments but the output we want
+ * is the post-processed versions of log/check, so we resort to tempfiles.
+ */
+ lazy val diffOutput = {
+ if (!checkFile.exists) "" else {
+ val input = diffCleanup(checkFile)
+ val output = diffCleanup(logFile)
+ def asFile(s: String) = returning(File.makeTemp("partest-diff"))(_ writeAll s)
+
+ if (input == output) ""
+ else diffFiles(asFile(input), asFile(output))
+ }
+ }
+ private def checkTraceName = tracePath(checkFile)
+ private def logTraceName = tracePath(logFile)
+ private def isDiffConfirmed = checkFile.exists && (diffOutput == "")
+
+ private def sendTraceMsg() {
+ def result =
+ if (isDryRun) ""
+ else if (isDiffConfirmed) " [passed]"
+ else if (checkFile.exists) " [failed]"
+ else " [unchecked]"
+
+ trace("diff %s %s%s".format(checkTraceName, logTraceName, result))
+ }
/** If optional is true, a missing check file is considered
* a successful diff. Necessary since many categories use
* checkfiles in an ad hoc manner.
*/
- def runDiff(check: File, log: File) = {
- def arg1 = tracePath(check)
- def arg2 = tracePath(log)
- def noCheck = !check.exists && returning(true)(_ => trace("diff %s %s [unchecked]".format(arg1, arg2)))
- def output = diffCleanup(log)
- def matches = safeSlurp(check).trim == output.trim
-
- def traceMsg =
- if (isDryRun) "diff %s %s".format(arg1, arg2)
- else "diff %s %s [%s]".format(arg1, arg2, (if (matches) "passed" else "failed"))
-
- noCheck || {
- trace(traceMsg)
-
- isDryRun || matches || (isUpdateCheck && {
- normal("** diff %s %s failed:\n".format(arg1, arg2))
- normal(diffOutput())
- normal("** updating %s and marking as passed.\n".format(arg1))
- check writeAll output
+ def runDiff() = {
+ sendTraceMsg()
+
+ def updateCheck = (
+ isUpdateCheck && {
+ val formatStr = "** diff %s %s: " + (
+ if (checkFile.exists) "failed, updating '%s' and marking as passed."
+ else if (diffOutput == "") "not creating checkFile at '%s' as there is no output."
+ else "was unchecked, creating '%s' for future tests."
+ ) + "\n"
+
+ normal(formatStr.format(checkTraceName, logTraceName, checkFile.path))
+ if (diffOutput != "") normal(diffOutput)
+
+ checkFile.writeAll(diffCleanup(logFile), "\n")
true
- })
- }
- }
+ }
+ )
- private def cleanedLog = returning(File makeTemp "partest-diff")(_ writeAll diffCleanup(logFile))
- def diffOutput(): String = checkFile ifFile (f => diffFiles(f, cleanedLog)) getOrElse ""
+ isDryRun || isDiffConfirmed || (updateCheck || !checkFile.exists)
+ }
}
}
diff --git a/src/partest/scala/tools/partest/Categories.scala b/src/partest/scala/tools/partest/Categories.scala
index c7a080dafe..172cca74b4 100644
--- a/src/partest/scala/tools/partest/Categories.scala
+++ b/src/partest/scala/tools/partest/Categories.scala
@@ -56,7 +56,7 @@ trait Categories {
* Category level or by individual tests.
*/
def compile: TestStep = (_: TestEntity).compile()
- def isCheckPresent: TestStep = (_: TestEntity).isCheckPresent
+ def checkFileRequired: TestStep = (_: TestEntity).checkFileRequired
def diff: TestStep = (_: TestEntity).diff()
def run: TestStep = (_: TestEntity).run()
def exec: TestStep = (_: TestEntity).exec()
diff --git a/src/partest/scala/tools/partest/Compilable.scala b/src/partest/scala/tools/partest/Compilable.scala
index 73dcdfce73..ddaa277842 100644
--- a/src/partest/scala/tools/partest/Compilable.scala
+++ b/src/partest/scala/tools/partest/Compilable.scala
@@ -43,18 +43,12 @@ trait PartestCompilation {
def scalac(args: List[String]): Boolean = {
val allArgs = assembleScalacArgs(args)
val (global, files) = newGlobal(allArgs)
- val foundFiles = execCwd match {
- case Some(cwd) => files map (x => File(cwd / x))
- case _ => files map (x => File(x))
- }
def nonFileArgs = if (isVerbose) global.settings.recreateArgs else assembleScalacArgs(Nil)
- def traceArgs = fromArgs(nonFileArgs ++ (foundFiles map tracePath))
- def traceMsg =
- if (isVerbose) "%s %s".format(build.scalaBin / "scalac", traceArgs)
- else "scalac " + traceArgs
+ def traceArgs = fromArgs(nonFileArgs ++ (files map tracePath))
+ def traceMsg = "scalac " + traceArgs
trace(traceMsg)
- isDryRun || global.partestCompile(foundFiles map (_.path), true)
+ isDryRun || global.partestCompile(files, true)
}
/** Actually running the test, post compilation.
@@ -71,7 +65,7 @@ trait PartestCompilation {
val cmd = fromArgs(javaCmdAndOptions ++ createPropertyString() ++ scalaCmdAndOptions)
def traceMsg = if (isVerbose) cmd else fromArgs(javaCmd :: args)
- trace(traceMsg)
+ trace("runScala: " + traceMsg)
isDryRun || execAndLog(cmd)
}
diff --git a/src/partest/scala/tools/partest/Config.scala b/src/partest/scala/tools/partest/Config.scala
index 288a3034e9..2ed096d930 100644
--- a/src/partest/scala/tools/partest/Config.scala
+++ b/src/partest/scala/tools/partest/Config.scala
@@ -15,7 +15,7 @@ trait Config {
lazy val src = absolutize(srcDir).toDirectory
lazy val build = new TestBuild()
- def javaHomeEnv = envOrElse("JAVA_HOME", null)
+ def javaHomeEnv = envOrElse("JAVA_HOME", "")
def javaCmd = envOrElse("JAVACMD", "java")
def javacCmd = Option(javaHomeEnv) map (x => Path(x) / "bin" / "javac" path) getOrElse "javac"
diff --git a/src/partest/scala/tools/partest/Entities.scala b/src/partest/scala/tools/partest/Entities.scala
index 2339250699..bea505b594 100644
--- a/src/partest/scala/tools/partest/Entities.scala
+++ b/src/partest/scala/tools/partest/Entities.scala
@@ -23,7 +23,7 @@ trait Entities {
def category: TestCategory
lazy val label = location.stripExtension
- lazy val testClasspath = returning(createClasspathString())(vtrace)
+ lazy val testClasspath = returning(createClasspathString())(x => vtrace("testClasspath: " + x))
/** Was this test successful? Calling this for the first time forces
* lazy val "process" which actually runs the test.
@@ -47,7 +47,6 @@ trait Entities {
*/
def argumentsToRun = List("Test", "jvm")
def argumentsToExec = List(location.path)
- def argumentsToDiff = ((checkFile, logFile))
/** Using a .cmds file for a custom test sequence.
*/
@@ -58,7 +57,7 @@ trait Entities {
def run() = runScala(argumentsToRun)
def exec() = runExec(argumentsToExec)
- def diff() = runDiff(argumentsToDiff._1, argumentsToDiff._2)
+ def diff() = runDiff() // checkFile, logFile
/** The memoized result of the test run.
*/
diff --git a/src/partest/scala/tools/partest/Partest.scala b/src/partest/scala/tools/partest/Partest.scala
index 7efac63354..b3fe9a98ef 100644
--- a/src/partest/scala/tools/partest/Partest.scala
+++ b/src/partest/scala/tools/partest/Partest.scala
@@ -29,12 +29,8 @@ class Partest(args: List[String]) extends {
lazy val testBuildDir = searchForDir(buildDir)
lazy val partestDir = searchForDir(rootDir)
lazy val allCategories = List(Pos, Neg, Run, Jvm, Res, Shootout, Scalap, Scalacheck, BuildManager, Script)
-
lazy val selectedCategories = if (isAllImplied) allCategories else specifiedCats
- // Coarse validation of partest directory: holds a file called partest.
- (partestDir / "partest").isFile || error("'%s' is not a valid partest directory." format partestDir)
-
def specifiedTests = parsed.residualArgs map (x => Path(x).normalize)
def specifiedKinds = testKinds filter (x => isSet(x) || (runSets contains x))
def specifiedCats = specifiedKinds flatMap (x => allCategories find (_.kind == x))
diff --git a/src/partest/scala/tools/partest/PartestSpec.scala b/src/partest/scala/tools/partest/PartestSpec.scala
index a89c30a14d..c25119b3af 100644
--- a/src/partest/scala/tools/partest/PartestSpec.scala
+++ b/src/partest/scala/tools/partest/PartestSpec.scala
@@ -17,7 +17,7 @@ import cmd._
*/
trait PartestSpec extends Spec with Meta.StdOpts with Interpolation {
def referenceSpec = PartestSpec
- def programInfo = Spec.Names("partest", "scala.tools.partest.Runner")
+ def programInfo = Spec.Info("partest", "", "scala.tools.partest.Runner")
private val kind = new Spec.Accumulator[String]()
protected def testKinds = kind.get
@@ -95,7 +95,6 @@ object PartestSpec extends PartestSpec with Property {
type ThisCommandLine = PartestCommandLine
class PartestCommandLine(args: List[String]) extends SpecCommandLine(args) {
- override def onlyKnownOptions = true
override def errorFn(msg: String) = printAndExit("Error: " + msg)
def propertyArgs = PartestSpec.propertyArgs
diff --git a/src/partest/scala/tools/partest/Results.scala b/src/partest/scala/tools/partest/Results.scala
index 8078e7bf85..5d0e300136 100644
--- a/src/partest/scala/tools/partest/Results.scala
+++ b/src/partest/scala/tools/partest/Results.scala
@@ -53,7 +53,7 @@ trait Results {
super.show(msg)
if (isShowDiff || isTrace)
- normal(entity.diffOutput())
+ normal(entity.diffOutput)
if (isShowLog || isTrace)
normal(toStringTrunc(entity.failureMessage(), 1600))
diff --git a/src/partest/scala/tools/partest/category/AllCategories.scala b/src/partest/scala/tools/partest/category/AllCategories.scala
index ecf0737cbe..953f80324b 100644
--- a/src/partest/scala/tools/partest/category/AllCategories.scala
+++ b/src/partest/scala/tools/partest/category/AllCategories.scala
@@ -14,7 +14,7 @@ trait AllCategories extends Compiler with Analysis with Runner {
self: Universe =>
object Pos extends DirBasedCategory("pos") { lazy val testSequence: TestSequence = List(compile) }
- object Neg extends DirBasedCategory("neg") { lazy val testSequence: TestSequence = List(isCheckPresent, not(compile), diff) }
+ object Neg extends DirBasedCategory("neg") { lazy val testSequence: TestSequence = List(checkFileRequired, not(compile), diff) }
object Run extends DirBasedCategory("run") { lazy val testSequence: TestSequence = List(compile, run, diff) }
object Jvm extends DirBasedCategory("jvm") { lazy val testSequence: TestSequence = List(compile, run, diff) }
}
diff --git a/src/partest/scala/tools/partest/category/Analysis.scala b/src/partest/scala/tools/partest/category/Analysis.scala
index d05ee6bb21..2c6c208ee5 100644
--- a/src/partest/scala/tools/partest/category/Analysis.scala
+++ b/src/partest/scala/tools/partest/category/Analysis.scala
@@ -32,7 +32,7 @@ trait Analysis {
self: Universe =>
object Scalap extends DirBasedCategory("scalap") {
- val testSequence: TestSequence = List(isCheckPresent, compile, run, diff)
+ val testSequence: TestSequence = List(checkFileRequired, compile, run, diff)
override def denotesTest(p: Path) = p.isDirectory && (p.toDirectory.files exists (_.name == "result.test"))
override def createTest(location: Path) = new ScalapTest(location)
diff --git a/src/partest/scala/tools/partest/category/Compiler.scala b/src/partest/scala/tools/partest/category/Compiler.scala
index 11112509cc..49775d5031 100644
--- a/src/partest/scala/tools/partest/category/Compiler.scala
+++ b/src/partest/scala/tools/partest/category/Compiler.scala
@@ -19,7 +19,7 @@ trait Compiler {
* $SCALAC -d dir.obj -Xresident -sourcepath . "$@"
*/
object Res extends DirBasedCategory("res") {
- lazy val testSequence: TestSequence = List(isCheckPresent, compile, diff)
+ lazy val testSequence: TestSequence = List(checkFileRequired, compile, diff)
override def denotesTest(p: Path) = p.isDirectory && resFile(p).isFile
override def createTest(location: Path) = new ResidentTest(location.toDirectory)
@@ -61,7 +61,7 @@ trait Compiler {
}
object BuildManager extends DirBasedCategory("buildmanager") {
- lazy val testSequence: TestSequence = List(isCheckPresent, compile, diff)
+ lazy val testSequence: TestSequence = List(checkFileRequired, compile, diff)
override def denotesTest(p: Path) = p.isDirectory && testFile(p).isFile
override def createTest(location: Path) = new BuildManagerTest(location.toDirectory)
@@ -123,7 +123,7 @@ trait Compiler {
def sendCommand(line: String): Boolean = {
val compileRegex = """^>>compile (.*)$""".r
val updateRegex = """^>>update\s+(.*)""".r
- trace(line drop 2)
+ trace("send: " + (line drop 2))
isDryRun || (line match {
case compileRegex(xs) => pbm.buildManagerCompile(xs)
diff --git a/src/partest/scala/tools/partest/io/Logging.scala b/src/partest/scala/tools/partest/io/Logging.scala
index d244d58757..52239ffb2c 100644
--- a/src/partest/scala/tools/partest/io/Logging.scala
+++ b/src/partest/scala/tools/partest/io/Logging.scala
@@ -55,15 +55,17 @@ trait Logging {
finally log.close()
}
- /** XXX needs attention.
+ /** What to print in a failure summary.
*/
- def failureMessage() = safeSlurp(logFile)
+ def failureMessage() = if (diffOutput != "") diffOutput else safeSlurp(logFile)
/** For tracing. Outputs a line describing the next action. tracePath
* is a path wrapper which prints name or full path depending on verbosity.
*/
- def trace(msg: String) = if (isTrace || isDryRun) System.err.println(">> [%s] %s".format(label, msg))
- def tracePath(path: Path) = if (isVerbose) path.path else path.name
+ def trace(msg: String) = if (isTrace || isDryRun) System.err.println(">> [%s] %s".format(label, msg))
+
+ def tracePath(path: Path): String = if (isVerbose) path.path else path.name
+ def tracePath(path: String): String = tracePath(Path(path))
/** v == verbose.
*/
diff --git a/src/scalap/scala/tools/scalap/Decode.scala b/src/scalap/scala/tools/scalap/Decode.scala
index e9f9a390c5..5189009584 100644
--- a/src/scalap/scala/tools/scalap/Decode.scala
+++ b/src/scalap/scala/tools/scalap/Decode.scala
@@ -12,7 +12,10 @@ package scala.tools.scalap
import scala.tools.scalap.scalax.rules.scalasig._
import scala.tools.nsc.util.ScalaClassLoader
import scala.tools.nsc.util.ScalaClassLoader.getSystemLoader
-import Main.SCALA_SIG
+import scala.reflect.generic.ByteCodecs
+
+import ClassFileParser.{ ConstValueIndex, Annotation }
+import Main.{ SCALA_SIG, SCALA_SIG_ANNOTATION, BYTES_VALUE }
/** Temporary decoder. This would be better off in the scala.tools.nsc
* but right now the compiler won't acknowledge scala.tools.scalap
@@ -25,7 +28,8 @@ object Decode {
case _ => NoSymbol
}
- /** Return the classfile bytes representing the scala sig attribute.
+ /** Return the classfile bytes representing the scala sig classfile attribute.
+ * This has been obsoleted by the switch to annotations.
*/
def scalaSigBytes(name: String): Option[Array[Byte]] = scalaSigBytes(name, getSystemLoader())
def scalaSigBytes(name: String, classLoader: ScalaClassLoader): Option[Array[Byte]] = {
@@ -35,6 +39,25 @@ object Decode {
cf.scalaSigAttribute map (_.data)
}
+ /** Return the bytes representing the annotation
+ */
+ def scalaSigAnnotationBytes(name: String): Option[Array[Byte]] = scalaSigAnnotationBytes(name, getSystemLoader())
+ def scalaSigAnnotationBytes(name: String, classLoader: ScalaClassLoader): Option[Array[Byte]] = {
+ val bytes = classLoader.findBytesForClassName(name)
+ val byteCode = ByteCode(bytes)
+ val classFile = ClassFileParser.parse(byteCode)
+ import classFile._
+
+ classFile annotation SCALA_SIG_ANNOTATION map { case Annotation(_, els) =>
+ val bytesElem = els find (x => constant(x.elementNameIndex) == BYTES_VALUE) get
+ val _bytes = bytesElem.elementValue match { case ConstValueIndex(x) => constantWrapped(x) }
+ val bytes = _bytes.asInstanceOf[StringBytesPair].bytes
+ val length = ByteCodecs.decode(bytes)
+
+ bytes take length
+ }
+ }
+
/** private[scala] so nobody gets the idea this is a supported interface.
*/
private[scala] def caseParamNames(path: String): Option[List[String]] = {
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala
index 3cb70ec04e..354e3131e8 100644
--- a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala
+++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala
@@ -17,6 +17,7 @@ import java.util.regex.Pattern
import scala.tools.scalap.scalax.util.StringUtil
import reflect.NameTransformer
+import java.lang.String
class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) {
import stream._
@@ -130,6 +131,7 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) {
val it = c.infoType
val classType = it match {
case PolyType(typeRef, symbols) => PolyTypeWithCons(typeRef, symbols, defaultConstructor)
+ case ClassInfoType(a, b) if c.isCase => ClassInfoTypeWithCons(a, b, defaultConstructor)
case _ => it
}
printType(classType)
@@ -368,6 +370,8 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) {
}
case RefinedType(classSym, typeRefs) => sep + typeRefs.map(toString).mkString("", " with ", "")
case ClassInfoType(symbol, typeRefs) => sep + typeRefs.map(toString).mkString(" extends ", " with ", "")
+ case ClassInfoTypeWithCons(symbol, typeRefs, cons) => sep + typeRefs.map(toString).
+ mkString(cons + " extends ", " with ", "")
case ImplicitMethodType(resultType, _) => toString(resultType, sep)
case MethodType(resultType, _) => toString(resultType, sep)
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Type.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Type.scala
index e224525d06..c991df6c09 100644
--- a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Type.scala
+++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Type.scala
@@ -15,6 +15,7 @@ case class TypeRefType(prefix : Type, symbol : Symbol, typeArgs : Seq[Type]) ext
case class TypeBoundsType(lower : Type, upper : Type) extends Type
case class RefinedType(classSym : Symbol, typeRefs : List[Type]) extends Type
case class ClassInfoType(symbol : Symbol, typeRefs : Seq[Type]) extends Type
+case class ClassInfoTypeWithCons(symbol : Symbol, typeRefs : Seq[Type], cons: String) extends Type
case class MethodType(resultType : Type, paramSymbols : Seq[Symbol]) extends Type
case class PolyType(typeRef : Type, symbols : Seq[TypeSymbol]) extends Type
case class PolyTypeWithCons(typeRef : Type, symbols : Seq[TypeSymbol], cons: String) extends Type
diff --git a/src/swing/scala/swing/EditorPane.scala b/src/swing/scala/swing/EditorPane.scala
index d90615299d..884da6a371 100644
--- a/src/swing/scala/swing/EditorPane.scala
+++ b/src/swing/scala/swing/EditorPane.scala
@@ -21,7 +21,7 @@ import java.awt.event._
* @see javax.swing.JEditorPane
*/
class EditorPane(contentType0: String, text0: String) extends TextComponent {
- override lazy val peer: JEditorPane = new JEditorPane(contentType0, text0) with SuperMixin {}
+ override lazy val peer: JEditorPane = new JEditorPane(contentType0, text0) with SuperMixin
def this() = this("text/plain", "")
def contentType: String = peer.getContentType
diff --git a/src/swing/scala/swing/FlowPanel.scala b/src/swing/scala/swing/FlowPanel.scala
index 5b2d1950a4..65833940f5 100644
--- a/src/swing/scala/swing/FlowPanel.scala
+++ b/src/swing/scala/swing/FlowPanel.scala
@@ -12,6 +12,7 @@
package scala.swing
import java.awt.FlowLayout
+import javax.swing.JPanel
object FlowPanel {
object Alignment extends Enumeration {
@@ -30,7 +31,8 @@ object FlowPanel {
* @see java.awt.FlowLayout
*/
class FlowPanel(alignment: FlowPanel.Alignment.Value)(contents0: Component*) extends Panel with SequentialContainer.Wrapper {
- override lazy val peer: javax.swing.JPanel = new javax.swing.JPanel(new java.awt.FlowLayout(alignment.id))
+ override lazy val peer: JPanel =
+ new JPanel(new java.awt.FlowLayout(alignment.id)) with SuperMixin
def this(contents0: Component*) = this(FlowPanel.Alignment.Center)(contents0: _*)
def this() = this(FlowPanel.Alignment.Center)()
diff --git a/src/swing/scala/swing/FormattedTextField.scala b/src/swing/scala/swing/FormattedTextField.scala
index c82c0fe45f..1a2d1dacb4 100644
--- a/src/swing/scala/swing/FormattedTextField.scala
+++ b/src/swing/scala/swing/FormattedTextField.scala
@@ -33,7 +33,7 @@ object FormattedTextField {
* @see javax.swing.JFormattedTextField
*/
class FormattedTextField(format: java.text.Format) extends TextComponent {
- override lazy val peer: JFormattedTextField = new JFormattedTextField(format)
+ override lazy val peer: JFormattedTextField = new JFormattedTextField(format) with SuperMixin
import FormattedTextField._
diff --git a/src/swing/scala/swing/GridBagPanel.scala b/src/swing/scala/swing/GridBagPanel.scala
index 5402d1f686..412ec3f4f5 100644
--- a/src/swing/scala/swing/GridBagPanel.scala
+++ b/src/swing/scala/swing/GridBagPanel.scala
@@ -11,7 +11,7 @@
package scala.swing
-import java.awt.{GridBagConstraints}
+import java.awt.{GridBagConstraints, GridBagLayout}
object GridBagPanel {
@@ -50,10 +50,10 @@ object GridBagPanel {
* @see java.awt.GridBagLayout
*/
class GridBagPanel extends Panel with LayoutContainer {
- override lazy val peer = new javax.swing.JPanel(new java.awt.GridBagLayout)
+ override lazy val peer = new javax.swing.JPanel(new GridBagLayout) with SuperMixin
import GridBagPanel._
- private def layoutManager = peer.getLayout.asInstanceOf[java.awt.GridBagLayout]
+ private def layoutManager = peer.getLayout.asInstanceOf[GridBagLayout]
/**
* Convenient conversion from xy-coords given as pairs to
diff --git a/src/swing/scala/swing/GridPanel.scala b/src/swing/scala/swing/GridPanel.scala
index b37f26221d..608b8810a2 100644
--- a/src/swing/scala/swing/GridPanel.scala
+++ b/src/swing/scala/swing/GridPanel.scala
@@ -21,7 +21,8 @@ object GridPanel {
* @see java.awt.GridLayout
*/
class GridPanel(rows0: Int, cols0: Int) extends Panel with SequentialContainer.Wrapper {
- override lazy val peer = new javax.swing.JPanel(new java.awt.GridLayout(rows0, cols0))
+ override lazy val peer =
+ new javax.swing.JPanel(new java.awt.GridLayout(rows0, cols0)) with SuperMixin
/*type Constraints = (Int, Int)
diff --git a/src/swing/scala/swing/Label.scala b/src/swing/scala/swing/Label.scala
index 2a24e8cd02..31b2b0c87c 100644
--- a/src/swing/scala/swing/Label.scala
+++ b/src/swing/scala/swing/Label.scala
@@ -20,7 +20,8 @@ import scala.swing.Swing._
* @see javax.swing.JLabel
*/
class Label(text0: String, icon0: Icon, align: Alignment.Value) extends Component {
- override lazy val peer: JLabel = new JLabel(text0, toNullIcon(icon0), align.id) with SuperMixin
+ override lazy val peer: JLabel =
+ new JLabel(text0, toNullIcon(icon0), align.id) with SuperMixin
def this() = this("", EmptyIcon, Alignment.Center)
def this(s: String) = this(s, EmptyIcon, Alignment.Center)
diff --git a/src/swing/scala/swing/ListView.scala b/src/swing/scala/swing/ListView.scala
index a15471796c..9c7b7d6d19 100644
--- a/src/swing/scala/swing/ListView.scala
+++ b/src/swing/scala/swing/ListView.scala
@@ -143,7 +143,7 @@ object ListView {
*/
class ListView[A] extends Component {
import ListView._
- override lazy val peer: JList = new JList
+ override lazy val peer: JList = new JList with SuperMixin
def this(items: Seq[A]) = {
this()
diff --git a/src/swing/scala/swing/MainFrame.scala b/src/swing/scala/swing/MainFrame.scala
index 361da6233b..ec4e74958b 100644
--- a/src/swing/scala/swing/MainFrame.scala
+++ b/src/swing/scala/swing/MainFrame.scala
@@ -18,5 +18,5 @@ import event._
* framework and quits the application when closed.
*/
class MainFrame extends Frame {
- override def closeOperation { System.exit(0); }
+ override def closeOperation { System.exit(0) }
}
diff --git a/src/swing/scala/swing/Menu.scala b/src/swing/scala/swing/Menu.scala
index 14855fd51f..55773320c6 100644
--- a/src/swing/scala/swing/Menu.scala
+++ b/src/swing/scala/swing/Menu.scala
@@ -24,7 +24,7 @@ object MenuBar {
* @see javax.swing.JMenuBar
*/
class MenuBar extends Component with SequentialContainer.Wrapper {
- override lazy val peer: JMenuBar = new JMenuBar
+ override lazy val peer: JMenuBar = new JMenuBar with SuperMixin
def menus: Seq[Menu] = contents.filter(_.isInstanceOf[Menu]).map(_.asInstanceOf[Menu])
diff --git a/src/swing/scala/swing/PasswordField.scala b/src/swing/scala/swing/PasswordField.scala
index 4b07969612..568cc3b927 100644
--- a/src/swing/scala/swing/PasswordField.scala
+++ b/src/swing/scala/swing/PasswordField.scala
@@ -21,7 +21,7 @@ import java.awt.event._
* @see javax.swing.JPasswordField
*/
class PasswordField(text0: String, columns0: Int) extends TextField(text0, columns0) {
- override lazy val peer: JPasswordField = new JPasswordField(text0, columns0)
+ override lazy val peer: JPasswordField = new JPasswordField(text0, columns0) with SuperMixin
def this(text: String) = this(text, 0)
def this(columns: Int) = this("", columns)
def this() = this("")
diff --git a/src/swing/scala/swing/ProgressBar.scala b/src/swing/scala/swing/ProgressBar.scala
index d43ddd5717..c6c2ae25d3 100644
--- a/src/swing/scala/swing/ProgressBar.scala
+++ b/src/swing/scala/swing/ProgressBar.scala
@@ -22,7 +22,7 @@ import event._
*/
class ProgressBar extends Component with Orientable.Wrapper {
override lazy val peer: javax.swing.JProgressBar =
- new javax.swing.JProgressBar
+ new javax.swing.JProgressBar with SuperMixin
def min: Int = peer.getMinimum
def min_=(v: Int) { peer.setMinimum(v) }
diff --git a/src/swing/scala/swing/RadioButton.scala b/src/swing/scala/swing/RadioButton.scala
index ae789b077c..3b3e60816b 100644
--- a/src/swing/scala/swing/RadioButton.scala
+++ b/src/swing/scala/swing/RadioButton.scala
@@ -21,6 +21,6 @@ import javax.swing._
* @see javax.swing.JRadioButton
*/
class RadioButton(text0: String) extends ToggleButton {
- override lazy val peer: JRadioButton = new JRadioButton(text0)
+ override lazy val peer: JRadioButton = new JRadioButton(text0) with SuperMixin
def this() = this("")
}
diff --git a/src/swing/scala/swing/ScrollBar.scala b/src/swing/scala/swing/ScrollBar.scala
index 2ae8cd5c4e..28245edda7 100644
--- a/src/swing/scala/swing/ScrollBar.scala
+++ b/src/swing/scala/swing/ScrollBar.scala
@@ -23,7 +23,7 @@ object ScrollBar {
}
class ScrollBar extends Component with Orientable.Wrapper with Adjustable.Wrapper {
- override lazy val peer = new JScrollBar
+ override lazy val peer: JScrollBar = new JScrollBar with SuperMixin
def valueIsAjusting = peer.getValueIsAdjusting
def valueIsAjusting_=(b : Boolean) = peer.setValueIsAdjusting(b)
diff --git a/src/swing/scala/swing/ScrollPane.scala b/src/swing/scala/swing/ScrollPane.scala
index fc2e96e67a..16c4130671 100644
--- a/src/swing/scala/swing/ScrollPane.scala
+++ b/src/swing/scala/swing/ScrollPane.scala
@@ -43,7 +43,7 @@ object ScrollPane {
class ScrollPane extends Component with Container {
import ScrollPane._
- override lazy val peer: JScrollPane = new JScrollPane
+ override lazy val peer: JScrollPane = new JScrollPane with SuperMixin
def this(c: Component) = {
this()
contents = c
diff --git a/src/swing/scala/swing/Separator.scala b/src/swing/scala/swing/Separator.scala
index cf2bfd75d0..4fdf0edb70 100644
--- a/src/swing/scala/swing/Separator.scala
+++ b/src/swing/scala/swing/Separator.scala
@@ -19,6 +19,6 @@ import javax.swing._
* @see javax.swing.JSeparator
*/
class Separator(o: Orientation.Value) extends Component with Oriented.Wrapper {
- override lazy val peer: JSeparator = new JSeparator(o.id)
+ override lazy val peer: JSeparator = new JSeparator(o.id) with SuperMixin
def this() = this(Orientation.Horizontal)
}
diff --git a/src/swing/scala/swing/Slider.scala b/src/swing/scala/swing/Slider.scala
index 793f5eb5bb..10b79f37cc 100644
--- a/src/swing/scala/swing/Slider.scala
+++ b/src/swing/scala/swing/Slider.scala
@@ -24,7 +24,7 @@ import event._
* @see javax.swing.JSlider
*/
class Slider extends Component with Orientable.Wrapper with Publisher {
- override lazy val peer: JSlider = new JSlider
+ override lazy val peer: JSlider = new JSlider with SuperMixin
def min: Int = peer.getMinimum
def min_=(v: Int) { peer.setMinimum(v) }
diff --git a/src/swing/scala/swing/SplitPane.scala b/src/swing/scala/swing/SplitPane.scala
index c9f1641ef7..bad3f32bed 100644
--- a/src/swing/scala/swing/SplitPane.scala
+++ b/src/swing/scala/swing/SplitPane.scala
@@ -23,7 +23,7 @@ import Swing._
*/
class SplitPane(o: Orientation.Value, left: Component, right: Component) extends Component with Container with Orientable.Wrapper {
override lazy val peer: javax.swing.JSplitPane =
- new javax.swing.JSplitPane(o.id, left.peer, right.peer)
+ new javax.swing.JSplitPane(o.id, left.peer, right.peer) with SuperMixin
def this(o: Orientation.Value) = this(o, new Component {}, new Component {})
def this() = this(Orientation.Horizontal)
diff --git a/src/swing/scala/swing/TabbedPane.scala b/src/swing/scala/swing/TabbedPane.scala
index b8fb1472fb..ec688a0cf0 100644
--- a/src/swing/scala/swing/TabbedPane.scala
+++ b/src/swing/scala/swing/TabbedPane.scala
@@ -77,7 +77,7 @@ object TabbedPane {
* @see javax.swing.JTabbedPane
*/
class TabbedPane extends Component with Publisher {
- override lazy val peer: JTabbedPane = new JTabbedPane
+ override lazy val peer: JTabbedPane = new JTabbedPane with SuperMixin
import TabbedPane._
object pages extends BufferWrapper[Page] {
diff --git a/src/swing/scala/swing/Table.scala b/src/swing/scala/swing/Table.scala
index 9370ea7eb1..2993f1d84e 100644
--- a/src/swing/scala/swing/Table.scala
+++ b/src/swing/scala/swing/Table.scala
@@ -110,7 +110,7 @@ object Table {
* @see javax.swing.JTable
*/
class Table extends Component with Scrollable.Wrapper {
- override lazy val peer: JTable = new JTable with Table.JTableMixin {
+ override lazy val peer: JTable = new JTable with Table.JTableMixin with SuperMixin {
def tableWrapper = Table.this
override def getCellRenderer(r: Int, c: Int) = new TableCellRenderer {
def getTableCellRendererComponent(table: JTable, value: AnyRef, isSelected: Boolean, hasFocus: Boolean, row: Int, column: Int) =
diff --git a/src/swing/scala/swing/TextArea.scala b/src/swing/scala/swing/TextArea.scala
index d491b0b0c6..201e4ab674 100644
--- a/src/swing/scala/swing/TextArea.scala
+++ b/src/swing/scala/swing/TextArea.scala
@@ -20,8 +20,9 @@ import java.awt.event._
*
* @see javax.swing.JTextArea
*/
-class TextArea(text0: String, rows0: Int, columns0: Int) extends TextComponent with TextComponent.HasColumns with TextComponent.HasRows {
- override lazy val peer: JTextArea = new JTextArea(text0, rows0, columns0)
+class TextArea(text0: String, rows0: Int, columns0: Int) extends TextComponent
+ with TextComponent.HasColumns with TextComponent.HasRows {
+ override lazy val peer: JTextArea = new JTextArea(text0, rows0, columns0) with SuperMixin
def this(text: String) = this(text, 0, 0)
def this(rows: Int, columns: Int) = this("", rows, columns)
def this() = this("", 0, 0)
diff --git a/src/swing/scala/swing/ToggleButton.scala b/src/swing/scala/swing/ToggleButton.scala
index 506f611c95..59f310dc23 100644
--- a/src/swing/scala/swing/ToggleButton.scala
+++ b/src/swing/scala/swing/ToggleButton.scala
@@ -21,6 +21,6 @@ import javax.swing._
* @see javax.swing.JToggleButton
*/
class ToggleButton(text0: String) extends AbstractButton {
- override lazy val peer: JToggleButton = new JToggleButton(text0)
+ override lazy val peer: JToggleButton = new JToggleButton(text0) with SuperMixin
def this() = this("")
}