summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntonio Cunei <antonio.cunei@epfl.ch>2010-04-29 11:39:00 +0000
committerAntonio Cunei <antonio.cunei@epfl.ch>2010-04-29 11:39:00 +0000
commit394ae087a71ff1e50827373dc73830c0fe799e3b (patch)
treeb430c1cfafe285dba5da226d5efac759c9330e73
parentedfac2904f29c7a9f32799fb8e37bd7a856b6b72 (diff)
downloadscala-394ae087a71ff1e50827373dc73830c0fe799e3b.tar.gz
scala-394ae087a71ff1e50827373dc73830c0fe799e3b.tar.bz2
scala-394ae087a71ff1e50827373dc73830c0fe799e3b.zip
Merged revisions 21575,21577,21596-21599,21603-...
Merged revisions 21575,21577,21596-21599,21603-21604,21606-21607,21611,21616,21620-21622, 21627-21629,21634-21635,21638-21640,21643-21645,21649-21650,21652,21655, 21660-21667,21671-21673,21675-21677,21679-21681,21684-21688,21690-21691, 21696-21697,21700-21712,21714,21720-21725,21729-21730,21735-21738 via svnmerge from https://lampsvn.epfl.ch/svn-repos/scala/scala/trunk ........ r21575 | dragos | 2010-04-14 11:35:50 +0200 (Wed, 14 Apr 2010) | 1 line Revert "Don't decode symbols in .toString." ........ r21577 | rytz | 2010-04-14 18:06:14 +0200 (Wed, 14 Apr 2010) | 1 line added scalacheck.jar and *.test files to the scala-test sbaz package. no review. ........ r21596 | extempore | 2010-04-15 17:23:49 +0200 (Thu, 15 Apr 2010) | 1 line A repl corner case. Closes #3298, no review. ........ r21597 | extempore | 2010-04-15 20:30:58 +0200 (Thu, 15 Apr 2010) | 4 lines Removed a bunch of -Y warning options. I intend to someday bring them back in the form of a compiler plugin. Also promoted -Yfatal-warnings to -Xfatal-warnings: this is key to writing tests which involve warnings and should be at least semi-supported. Closes #3300, no review. ........ r21598 | extempore | 2010-04-15 23:58:47 +0200 (Thu, 15 Apr 2010) | 3 lines Initialization ordering issue in BigDecimal. (More of these may be slipping by because -Xcheckinit doesn't work since specialization began.) No review. ........ r21599 | extempore | 2010-04-16 00:18:15 +0200 (Fri, 16 Apr 2010) | 3 lines Improved @tailrec error messages to specify the reason. In the process fixed old bug involving tail call transformation. Closes #3275, #2018. Review by dragos. ........ r21603 | extempore | 2010-04-16 03:53:46 +0200 (Fri, 16 Apr 2010) | 1 line Added a test to make sure distinct preserves ordering. No review ........ r21604 | extempore | 2010-04-16 05:26:33 +0200 (Fri, 16 Apr 2010) | 3 lines More polishing up features in partest which worked somewhere along the way but not at the end. This time it is unknown options: now it will complain. Closes #3289, no review. ........ r21606 | extempore | 2010-04-16 20:32:49 +0200 (Fri, 16 Apr 2010) | 3 lines Made partest diff algorithm much more lenient. Altered partest --update-check to create the check file if none exists as well as updating a pre-existing one. No review. ........ r21607 | extempore | 2010-04-16 20:34:02 +0200 (Fri, 16 Apr 2010) | 2 lines Degeneralized some incomplete generalization of the diff machinery. Improved the summary output on failures. No review. ........ r21611 | extempore | 2010-04-17 21:44:24 +0200 (Sat, 17 Apr 2010) | 1 line Fix and test case for forwarder duplicate bug. Closes #3004, no review. ........ r21616 | extempore | 2010-04-18 21:10:58 +0200 (Sun, 18 Apr 2010) | 2 lines Raised some partest timeouts, I think with these we might see the windows nightly pass. No review. ........ r21620 | plocinic | 2010-04-19 14:46:23 +0200 (Mon, 19 Apr 2010) | 1 line Better fix for #2757. Review by milessabin. ........ r21621 | dcaoyuan | 2010-04-19 17:16:53 +0200 (Mon, 19 Apr 2010) | 1 line Fixed #3322wq ........ r21622 | plocinic | 2010-04-19 17:33:39 +0200 (Mon, 19 Apr 2010) | 1 line Missing bit from r21620. In-memory classes need to be treated in the old way. ........ r21627 | rytz | 2010-04-20 15:08:52 +0200 (Tue, 20 Apr 2010) | 1 line fix bootstrap library build. review by odersky ........ r21628 | extempore | 2010-04-20 20:07:43 +0200 (Tue, 20 Apr 2010) | 2 lines More fully integrate immutable.Queue into collections. Fixes issue with return type of methods being Seq. Closes #3297, no review. ........ r21629 | extempore | 2010-04-20 20:07:54 +0200 (Tue, 20 Apr 2010) | 2 lines Undeprecated @retain as suggested by odersky on scala-internals 3/24/10. No review. ........ r21634 | extempore | 2010-04-21 07:08:25 +0200 (Wed, 21 Apr 2010) | 6 lines Handled action items (1) and (4) of the phaller/cunei/rytz agenda for a less regressive partest, to the extent possible without some accompanying sbaz changes. Unnecessary sanity check which failed on sane but non-trunk filesystem layouts removed. Files with custom command sequences explicitly qualify the path to the filenames listed in the .cmds file. Review by phaller. ........ r21635 | extempore | 2010-04-21 07:28:07 +0200 (Wed, 21 Apr 2010) | 3 lines Fixed bug in update method visibility which caused x += y not to find x's update method when defined generically. Closes #3278. Already reviewed by odersky. ........ r21638 | dragos | 2010-04-21 16:00:50 +0200 (Wed, 21 Apr 2010) | 1 line Fixed retyping of ThisTypes and less aggressive calls to makeNotPrivate ........ r21639 | dragos | 2010-04-21 16:00:54 +0200 (Wed, 21 Apr 2010) | 4 lines Changed the way special overrides are implemented. Instead of duplicating the source tree, it is moved from the generic method to its specialized variant. The owners are changed, and value/type parameter symbols are updated. This should fix most bugs involving call-by-name parameters. ........ r21640 | dubochet | 2010-04-21 16:38:57 +0200 (Wed, 21 Apr 2010) | 1 line [scaladoc] Slight change to design of how CommentFactory and ModelFactory are mixed together. Okayed by Pedro. ........ r21643 | extempore | 2010-04-21 19:06:38 +0200 (Wed, 21 Apr 2010) | 5 lines Since pickled data moved into annotations ShowPickled has been confusedly scratching its head. Made tools/showPickled work again. In the process created a simple interface for creating command line tools for the (majority of) commands which would just like to specify a handful of options. No review. ........ r21644 | extempore | 2010-04-21 19:06:59 +0200 (Wed, 21 Apr 2010) | 32 lines Two new command line programs in ~/tools: scmp and tokens. 1) scmp: will need a bit more fleshing out to be super useful, but here is what you can do right now: // This means run the given command line first with the options // given to p1 and then without, and show the diff in output. % tools/scmp --p1 '-no-specialization -nowarn' scalac -Ydebug src/library/scala/Function1.scala Upcoming features will involve seeing diffs of such things as the pickled signatures of generated files and the javap disassembly. 2) tokens: tokenizes all the scala files found under any given paths and prints one token per line. Example: the five most frequently used tokens under scala/util. % tools/tokens src/library/scala/util |sort | uniq -c | sort -r | head -5 598 ')' 598 '(' 347 ; 294 '=' 278 , Good to see those parens are balanced. Example: number of appearances of an identifier called x: % tools/tokens src/library/scala/util | grep ^x$ | wc 137 Way to go, x. Review by community. ........ r21645 | extempore | 2010-04-21 21:44:45 +0200 (Wed, 21 Apr 2010) | 2 lines Fixed a couple bugs in tools/tokens which were mysteriously more visible once it was checked in. No review. ........ r21649 | extempore | 2010-04-22 01:11:43 +0200 (Thu, 22 Apr 2010) | 10 lines Added two options to tools/tokens, --sliding and --freq. Using both: % tools/tokens --sliding 10 --freq src/compiler/scala/tools/nsc/typechecker | head -5 34 'if' '(' settings '.' debug '.' value ')' log '(' 17 scala '.' tools '.' nsc ; 'package' typechecker ;; 'import' 17 'package' scala '.' tools '.' nsc ; 'package' typechecker ;; 16 '}' 'package' scala '.' tools '.' nsc ; 'package' typechecker 15 ')' '{' 'if' '(' settings '.' debug '.' value ')' No review. ........ r21650 | phaller | 2010-04-22 10:04:12 +0200 (Thu, 22 Apr 2010) | 1 line Reactor.exceptionHandler is defined on Throwable instead of Exception. Fixes potential problem with visibility of changes to a field. Review by plocinic. ........ r21652 | phaller | 2010-04-22 12:26:29 +0200 (Thu, 22 Apr 2010) | 1 line Reverted change of Reactor.exceptionHandler's type of see r21650. Review by plocinic. ........ r21655 | plocinic | 2010-04-22 16:48:46 +0200 (Thu, 22 Apr 2010) | 1 line Some cleanup I did when looking at #2769. ........ r21660 | odersky | 2010-04-23 14:31:33 +0200 (Fri, 23 Apr 2010) | 1 line Fixed implicits problem in specs; Manifest[Class[_]] can now be generated. review by dubochet. ........ r21661 | odersky | 2010-04-23 14:34:44 +0200 (Fri, 23 Apr 2010) | 1 line Fixed typo in error message. No review. ........ r21662 | odersky | 2010-04-23 15:11:03 +0200 (Fri, 23 Apr 2010) | 1 line Fixed potential duplicate error annotation "Error occurred in an application involving default arguments." ........ r21663 | imaier | 2010-04-23 16:07:29 +0200 (Fri, 23 Apr 2010) | 1 line added missing SuperMixins ........ r21664 | plocinic | 2010-04-23 17:14:24 +0200 (Fri, 23 Apr 2010) | 1 line Closes #3108 plus removed some semicolons. No review. ........ r21665 | plocinic | 2010-04-23 17:14:27 +0200 (Fri, 23 Apr 2010) | 1 line Added test for #3081. No review. ........ r21666 | extempore | 2010-04-23 23:20:14 +0200 (Fri, 23 Apr 2010) | 16 lines Created Mutable and Immutable SetFactories to deal with the spectacular performance regression which accompanies the use of AddingBuilder on mutable Sets. Because '+' now creates a new collection even on mutable sets, AddingBuilder on a 100K element collection will create garbage sets of size 1,2,3...,99,999 before finishing. Thankfully there is already GrowingBuilder. See test/files/run/adding-growing-set.scala for a demonstration. This patch is not complete: in particular, SortedSet and SetBuilder need attention. Unfortunately there is a combinatorial jump in the number of Addable/Growable divisions which arises once one tries to accomodate both Sorted signatures (taking an Ordering) and unsorted signatures, so will come back to it after receiving counsel. Review by odersky. ........ r21667 | extempore | 2010-04-24 00:13:41 +0200 (Sat, 24 Apr 2010) | 4 lines Added size hints to Array.{ iterate, range, tabulate, fill }. Probably closes #3331, but it would be nice if someone would measure whether it makes much difference to skip the builder entirely in those cases where that could be done. No review. ........ r21671 | extempore | 2010-04-24 04:49:34 +0200 (Sat, 24 Apr 2010) | 2 lines Took another of universal equality's victims to the hospital. Closes #3348, no review. ........ r21672 | extempore | 2010-04-24 09:01:47 +0200 (Sat, 24 Apr 2010) | 8 lines StringBuilder no longer violates the Seq reverse contract: it returns a new StringBuilder. The behavior formerly found in reverse (updates in place) is now available in reverseContents. Migration warning on reverse. Closes #3327. Also did some StringBuilder rewriting as per discussion with odersky. And took a cleaver to parts of the documentation to get to the good parts a little faster. Review by community. ........ r21673 | extempore | 2010-04-24 17:17:41 +0200 (Sat, 24 Apr 2010) | 2 lines Another guess falling somewhere between educated and wild as to how to get the auxjvm nightly passing again. No review. ........ r21675 | rytz | 2010-04-25 08:23:11 +0200 (Sun, 25 Apr 2010) | 1 line close #3338, close #3334, close #3345. review by community. ........ r21676 | phaller | 2010-04-25 18:50:01 +0200 (Sun, 25 Apr 2010) | 1 line Closes #3356. Removes ad-hoc exception propagation logic from ActorCanReply.!!. Review by prokopec. ........ r21677 | prokopec | 2010-04-25 21:58:01 +0200 (Sun, 25 Apr 2010) | 1 line Fixes #3350. review by extempore ........ r21679 | extempore | 2010-04-26 01:20:59 +0200 (Mon, 26 Apr 2010) | 19 lines Some overdue improvements in repl completion, which has been largely awol since the pickler format change. Where possible, completion is now done using the compiler's internal model rather than reflection. Many handy things now work which did not before, such as wildcard imports causing all imported identifiers to henceforth be completable. Note also that there is a verbosity counter now, so hitting tab twice may yield more results than hitting it once. scala> import java.util.concurrent.atomic._ import java.util.concurrent.atomic._ scala> Atomic<tab><tab> AtomicBoolean AtomicInteger AtomicIntegerArray AtomicIntegerFieldUpdater AtomicLong AtomicLongArray [etc] Review by community. ........ r21680 | rytz | 2010-04-26 10:17:22 +0200 (Mon, 26 Apr 2010) | 1 line moved AnnotationDefaultAttr to scala.runtime. no review. ........ r21681 | odersky | 2010-04-26 12:15:37 +0200 (Mon, 26 Apr 2010) | 1 line Solves the "same type after erasure problem" uncovered by Derek. Review by rytz. ........ r21684 | dubochet | 2010-04-26 15:10:06 +0200 (Mon, 26 Apr 2010) | 1 line Improved documentation for `NodeSeq.\` and `NodeSeq.\\` (#3328). No review. ........ r21685 | dubochet | 2010-04-26 15:11:22 +0200 (Mon, 26 Apr 2010) | 1 line Better positioned regular expression parser, contributed by "asloane" (#3254). No review. ........ r21686 | malayeri | 2010-04-26 15:13:41 +0200 (Mon, 26 Apr 2010) | 1 line [scaladoc] Fix alignment of "Inherited" and "Visibility" labels in the page filter area. Review by dubochet. ........ r21687 | malayeri | 2010-04-26 15:19:46 +0200 (Mon, 26 Apr 2010) | 1 line [scaladoc] Added missing file for previous commit. ........ r21688 | malayeri | 2010-04-26 15:24:12 +0200 (Mon, 26 Apr 2010) | 1 line [scaladoc] Added TODO comments for later fixing issue that sourceless templates are not documented. No review. ........ r21690 | malayeri | 2010-04-26 15:30:09 +0200 (Mon, 26 Apr 2010) | 1 line [scaladoc] Moved object/template icons to the left of the link in the index. Review by dubochet. ........ r21691 | malayeri | 2010-04-26 15:33:41 +0200 (Mon, 26 Apr 2010) | 1 line [scaladoc] Removed commented-out items in the css, which should have just been removed in the first place. No review. ........ r21696 | prokopec | 2010-04-26 22:34:57 +0200 (Mon, 26 Apr 2010) | 1 line Typo patrol. no review ........ r21697 | extempore | 2010-04-26 22:42:03 +0200 (Mon, 26 Apr 2010) | 16 lines Mostly finishing the ball that got rolling in r21679. scala> String.cop<tab> scala> String.copyValueOf<tab> def copyValueOf(Array[Char]): String def copyValueOf(Array[Char], Int, Int): String scala> Nil.mkString<tab><tab> def mkString(sep: String): String def mkString(start: String, sep: String, end: String): String def mkString: String Lines which are not simply delimited don't work yet, so don't go expecting List(1).<tab> to do the right thing. Yet. No review. ........ r21700 | extempore | 2010-04-27 09:21:29 +0200 (Tue, 27 Apr 2010) | 1 line Some cleanups in repl completion and power mode. No review. ........ r21701 | extempore | 2010-04-27 09:40:17 +0200 (Tue, 27 Apr 2010) | 1 line Fixing the test I broke with the last commit. No review. ........ r21702 | moors | 2010-04-27 16:04:02 +0200 (Tue, 27 Apr 2010) | 5 lines fixed #3349 : method symbol cached too aggressively cooking raw types changes a symbol's info, but the change was masked by caching in MethodSymbol review by odersky ........ r21703 | dragos | 2010-04-27 17:08:57 +0200 (Tue, 27 Apr 2010) | 1 line Fixed crash when calling super in a closure (see #3312). Closes #3325. No review. ........ r21704 | dragos | 2010-04-27 17:09:00 +0200 (Tue, 27 Apr 2010) | 2 lines Fixed construction of specialized classes in the presence of side-effects and non-trivial initializers. Review by odersky. ........ r21705 | dragos | 2010-04-27 17:09:04 +0200 (Tue, 27 Apr 2010) | 1 line Added test for several tickets that were fixed earlier this week. no review. ........ r21706 | extempore | 2010-04-27 18:36:39 +0200 (Tue, 27 Apr 2010) | 7 lines Created TypeDiagnostics trait and have begun opportunistically moving code into it. Along the way, some improvements to error messages. The situation described in ticket #2206 has always had an applicable error message, but it wasn't making it out to the user. More kinds of ambiguity are disambiguated, see the test cases. And overload errors are printed with some formatting so one has some hope of parsing. Review by odersky. ........ r21707 | dragos | 2010-04-27 19:06:00 +0200 (Tue, 27 Apr 2010) | 1 line Fixed broken test file. No review. ........ r21708 | extempore | 2010-04-27 20:39:45 +0200 (Tue, 27 Apr 2010) | 2 lines Various refinements and polishing to do with method signature completion. No review. ........ r21709 | odersky | 2010-04-27 21:18:36 +0200 (Tue, 27 Apr 2010) | 2 lines Closes #3362. Review by dragos. ........ r21710 | extempore | 2010-04-27 21:27:04 +0200 (Tue, 27 Apr 2010) | 2 lines Added size hints to builders where possible without introducing new methods. Closes #3331, review by community. ........ r21711 | extempore | 2010-04-27 23:31:05 +0200 (Tue, 27 Apr 2010) | 1 line A small error message improvement suggested at #3092. No review. ........ r21712 | phaller | 2010-04-28 00:10:36 +0200 (Wed, 28 Apr 2010) | 1 line Fixed scaladoc output for several types and members. No review. ........ r21714 | rytz | 2010-04-28 11:37:03 +0200 (Wed, 28 Apr 2010) | 1 line no inlining on msil. this will fix msil build. no review ........ r21720 | ilyas | 2010-04-28 14:29:26 +0200 (Wed, 28 Apr 2010) | 1 line scalap: signature for case classes fixed ........ r21721 | phaller | 2010-04-28 15:28:45 +0200 (Wed, 28 Apr 2010) | 1 line Closes #3364. No review. ........ r21722 | phaller | 2010-04-28 17:26:22 +0200 (Wed, 28 Apr 2010) | 1 line Closes #3365. Adds test for new code. Review by prokopec. ........ r21723 | extempore | 2010-04-28 17:31:17 +0200 (Wed, 28 Apr 2010) | 17 lines Added classes/continuations-plugin to the plugin build classpath. Explanation: as things stood the plugin step of the overall build fails constantly even when no files have been touched. The reason is that if one checks out an older version of the repository and then returns to the master, a subset of continuation source files will have more recent modification dates than their corresponding classes, and ant sees that as a reason to rebuild them. But without continuations-plugin on the classpath, it cannot see the classfiles of those which were not changed. IOW, if a project has A.scala B.scala C.scala and tries to rebuild only A.scala and C.scala, B.class must be somewhere it can be seen. We can resolve this differently if desired but this is how the rest of the compiler does it. (Try removing quick from quick's classpath and rebuilding after some changes.) Review by rompf. ........ r21724 | extempore | 2010-04-28 20:42:26 +0200 (Wed, 28 Apr 2010) | 3 lines Some path-dependent type fiddling so power mode Trees don't come back typed _5.compiler.Tree forSome { val _5: scala.tools.nsc.Interpreter } or similar. No review. ........ r21725 | extempore | 2010-04-28 22:30:48 +0200 (Wed, 28 Apr 2010) | 3 lines Fixed bug in Iterator.iterate which would lead to a runtime exception under some circumstances due to inadequate laziness in calculating the next element. No review. ........ r21729 | rytz | 2010-04-29 08:37:18 +0200 (Thu, 29 Apr 2010) | 1 line improved doc for PARAMACCESSOR flag. no review ........ r21730 | rytz | 2010-04-29 10:09:38 +0200 (Thu, 29 Apr 2010) | 1 line fix msil backend. no review ........ r21735 | phaller | 2010-04-29 10:51:32 +0200 (Thu, 29 Apr 2010) | 1 line Closes #3369. Review by plocinic. ........ r21736 | phaller | 2010-04-29 11:00:51 +0200 (Thu, 29 Apr 2010) | 1 line UncaughtException is now a case class (see #2017). Review by plocinic. ........ r21737 | phaller | 2010-04-29 11:17:24 +0200 (Thu, 29 Apr 2010) | 1 line Removes scala.concurrent.AsyncInvokable, which is superseded by scala.actors.CanReply. No review. ........ r21738 | phaller | 2010-04-29 11:44:30 +0200 (Thu, 29 Apr 2010) | 1 line Made internal helper methods in concurrent.ops private. Removed protected tryCatch helper method from concurrent.TaskRunner. Review by rompf. ........
-rw-r--r--build.xml4
-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
-rw-r--r--test/files/buildmanager/t2790/t2790.check2
-rw-r--r--test/files/jvm/actor-exceptions.check4
-rw-r--r--test/files/jvm/actor-exceptions.scala8
-rw-r--r--test/files/jvm/actor-link-getstate.check3
-rw-r--r--test/files/jvm/actor-uncaught-exception.check7
-rw-r--r--test/files/jvm/actor-uncaught-exception.scala1
-rw-r--r--test/files/jvm/actor-uncaught-exception2.scala1
-rw-r--r--test/files/jvm/annotations.scala3
-rw-r--r--test/files/jvm/t3356.check1
-rw-r--r--test/files/jvm/t3356.scala54
-rw-r--r--test/files/jvm/t3365.check5
-rw-r--r--test/files/jvm/t3365.scala65
-rw-r--r--test/files/neg/bug2206.check5
-rw-r--r--test/files/neg/bug2206.scala15
-rw-r--r--test/files/neg/bug278.check5
-rw-r--r--test/files/neg/illegal-stmt-start.check4
-rw-r--r--test/files/neg/illegal-stmt-start.scala5
-rw-r--r--test/files/neg/migration28.flags2
-rw-r--r--test/files/neg/names-defaults-neg.check4
-rw-r--r--test/files/neg/overload-msg.check13
-rw-r--r--test/files/neg/overload-msg.scala4
-rw-r--r--test/files/neg/t3115.flags2
-rw-r--r--test/files/neg/tailrec.check18
-rw-r--r--test/files/neg/tailrec.scala44
-rw-r--r--test/files/neg/typeerror.check2
-rw-r--r--test/files/pos/bug2018.scala15
-rw-r--r--test/files/pos/bug3097.flags2
-rw-r--r--test/files/pos/bug3278.scala15
-rw-r--r--test/files/pos/implicits.scala5
-rw-r--r--test/files/pos/spec-traits.scala83
-rw-r--r--test/files/pos/t3108.scala5
-rw-r--r--test/files/pos/t3349/AbstractTupleSet.java9
-rw-r--r--test/files/pos/t3349/Table.java9
-rw-r--r--test/files/pos/t3349/Test.scala5
-rw-r--r--test/files/pos/t3349/TupleSet.java4
-rw-r--r--test/files/run/adding-growing-set.scala11
-rw-r--r--test/files/run/bug3004.scala14
-rw-r--r--test/files/run/bug3327.check1
-rw-r--r--test/files/run/bug3327.scala8
-rw-r--r--test/files/run/distinct.check1
-rw-r--r--test/files/run/distinct.scala15
-rw-r--r--test/files/run/iterator-iterate-lazy.scala5
-rw-r--r--test/files/run/mapValues.scala8
-rw-r--r--test/files/run/names-defaults.scala21
-rw-r--r--test/files/run/spec-early.check4
-rw-r--r--test/files/run/spec-early.scala15
-rw-r--r--test/files/run/spec-init.check9
-rw-r--r--test/files/run/spec-init.scala41
-rw-r--r--test/files/run/stream_length.scala15
-rw-r--r--test/files/run/stringbuilder.scala8
-rw-r--r--test/files/run/treePrint.scala2
-rw-r--r--test/pending/run/string-reverse.scala22
-rwxr-xr-xtools/scmp4
-rwxr-xr-xtools/tokens4
217 files changed, 3348 insertions, 2362 deletions
diff --git a/build.xml b/build.xml
index 9bc22ae539..35e4889199 100644
--- a/build.xml
+++ b/build.xml
@@ -617,6 +617,7 @@ QUICK BUILD (QUICK)
<compilationpath>
<pathelement location="${build-quick.dir}/classes/library"/>
<pathelement location="${build-quick.dir}/classes/compiler"/>
+ <pathelement location="${build-quick.dir}/classes/continuations-plugin"/>
</compilationpath>
</scalacfork>
<copy
@@ -1500,6 +1501,9 @@ BOOTRAPING TEST AND TEST SUITE
<target name="test.suite" depends="pack.done">
<partest classpathref="pack.classpath">
<env key="PATH" path="${build-pack.dir}/bin:${env.PATH}" />
+ <sysproperty key="partest.timeout" value="14400" />
+ <sysproperty key="partest.test-warning" value="150" />
+ <sysproperty key="partest.test-timeout" value="1200" />
<sysproperty key="partest.srcdir" value="files" />
<sysproperty key="partest.scalacopts" value="${scalac.args.all}" />
<sysproperty key="partest.javacopts" value="${javac.args}" />
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("")
}
diff --git a/test/files/buildmanager/t2790/t2790.check b/test/files/buildmanager/t2790/t2790.check
index 065956765a..3a57d28817 100644
--- a/test/files/buildmanager/t2790/t2790.check
+++ b/test/files/buildmanager/t2790/t2790.check
@@ -9,6 +9,6 @@ compiling Set(B.scala)
B.scala:2: error: type mismatch;
found : Int(5)
required: String
-Error occured in an application involving default arguments.
+Error occurred in an application involving default arguments.
val y = A.x(5)
^
diff --git a/test/files/jvm/actor-exceptions.check b/test/files/jvm/actor-exceptions.check
index bd44b968cc..d86bac9de5 100644
--- a/test/files/jvm/actor-exceptions.check
+++ b/test/files/jvm/actor-exceptions.check
@@ -1,3 +1 @@
-Uncaught exception in Slave
-Message: A
-MyOtherException
+OK
diff --git a/test/files/jvm/actor-exceptions.scala b/test/files/jvm/actor-exceptions.scala
index 384226d777..3ee4db9ed2 100644
--- a/test/files/jvm/actor-exceptions.scala
+++ b/test/files/jvm/actor-exceptions.scala
@@ -19,6 +19,7 @@ object Master extends Actor {
for (i <- 0 until 10) Slave ! A
react {
case Exit(from, reason) =>
+ println("OK")
}
} catch {
case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] =>
@@ -31,6 +32,7 @@ object Slave extends Actor {
override def toString = "Slave"
override def exceptionHandler: PartialFunction[Exception, Unit] = {
case MyException(text) =>
+ case other if !other.isInstanceOf[scala.util.control.ControlThrowable] => super.exceptionHandler(other)
}
def act() {
try {
@@ -41,12 +43,14 @@ object Slave extends Actor {
cnt += 1
if (cnt % 2 != 0) throw MyException("problem")
if (cnt == 10) {
- throw new MyOtherException("unhandled")
+ throw MyOtherException("unhandled")
}
}
}
} catch {
- case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] =>
+ case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] &&
+ !e.isInstanceOf[MyException] &&
+ !e.isInstanceOf[MyOtherException] =>
e.printStackTrace()
}
}
diff --git a/test/files/jvm/actor-link-getstate.check b/test/files/jvm/actor-link-getstate.check
index 45967222e6..9755447320 100644
--- a/test/files/jvm/actor-link-getstate.check
+++ b/test/files/jvm/actor-link-getstate.check
@@ -1,5 +1,2 @@
Done
-Uncaught exception in Master
-Message: 'done
-MyException: Master crashed
Terminated
diff --git a/test/files/jvm/actor-uncaught-exception.check b/test/files/jvm/actor-uncaught-exception.check
index 3e669779df..2c94e48371 100644
--- a/test/files/jvm/actor-uncaught-exception.check
+++ b/test/files/jvm/actor-uncaught-exception.check
@@ -1,5 +1,2 @@
-Uncaught exception in StartError
-MyException: I don't want to run!
-Uncaught exception in MessageError
-Message: 'ping
-MyException: No message for me!
+OK
+OK
diff --git a/test/files/jvm/actor-uncaught-exception.scala b/test/files/jvm/actor-uncaught-exception.scala
index 9dbd36dd82..882362272d 100644
--- a/test/files/jvm/actor-uncaught-exception.scala
+++ b/test/files/jvm/actor-uncaught-exception.scala
@@ -43,6 +43,7 @@ object Test {
Actor.loop {
react {
case Exit(actor, reason) =>
+ println("OK")
if (actor == StartError)
MessageError ! 'ping
else
diff --git a/test/files/jvm/actor-uncaught-exception2.scala b/test/files/jvm/actor-uncaught-exception2.scala
index 626ce5da92..36b6f0c52e 100644
--- a/test/files/jvm/actor-uncaught-exception2.scala
+++ b/test/files/jvm/actor-uncaught-exception2.scala
@@ -58,7 +58,6 @@ object Test {
}
def main(args: Array[String]) {
- Debug.level = 1 // decrease level so that it does not print warnings
Supervisor.start()
}
}
diff --git a/test/files/jvm/annotations.scala b/test/files/jvm/annotations.scala
index 227bd919c1..12760beb4e 100644
--- a/test/files/jvm/annotations.scala
+++ b/test/files/jvm/annotations.scala
@@ -160,6 +160,9 @@ object Test5 {
}
}
+// #3345
+class A3345(@volatile private var i:Int)
+
object Test {
def main(args: Array[String]) {
Test1.run
diff --git a/test/files/jvm/t3356.check b/test/files/jvm/t3356.check
new file mode 100644
index 0000000000..6a9284d0aa
--- /dev/null
+++ b/test/files/jvm/t3356.check
@@ -0,0 +1 @@
+sending download requests
diff --git a/test/files/jvm/t3356.scala b/test/files/jvm/t3356.scala
new file mode 100644
index 0000000000..5626281e7d
--- /dev/null
+++ b/test/files/jvm/t3356.scala
@@ -0,0 +1,54 @@
+import scala.actors.{Actor, Exit, !, UncaughtException}
+import Actor._
+
+case class ImageInfo(text: String) {
+ def downloadImage(): ImageData = {
+ ImageData(text)
+ }
+}
+
+case class ImageData(text: String)
+case class Download(info: ImageInfo)
+
+object Test {
+
+ def scanForImageInfo(url: String): List[ImageInfo] =
+ List(ImageInfo("A"), ImageInfo("B"))
+
+ def renderImage(data: ImageData) {
+ println("rendering image "+data.text)
+ }
+
+ def renderImages(url: String) {
+ val imageInfos = scanForImageInfo(url)
+ println("sending download requests")
+ val dataFutures = for (info <- imageInfos) yield {
+ val loader = link {
+ react { case Download(info) =>
+ throw new Exception("no connection")
+ reply(info.downloadImage())
+ }; {}
+ }
+ loader !! Download(info)
+ }
+ var i = 0
+ loopWhile (i < imageInfos.size) {
+ i += 1
+ val FutureInput = dataFutures(i-1).inputChannel
+ react {
+ case FutureInput ! (data @ ImageData(_)) =>
+ renderImage(data)
+ case Exit(from, UncaughtException(_, Some(Download(info)), _, _, cause)) =>
+ println("Couldn't download image "+info+" because of "+cause)
+ }
+ }
+ println("OK, all images rendered.")
+ }
+
+ def main(args: Array[String]) {
+ actor {
+ renderImages("panorama.epfl.ch")
+ }
+ }
+
+}
diff --git a/test/files/jvm/t3365.check b/test/files/jvm/t3365.check
new file mode 100644
index 0000000000..0944b17279
--- /dev/null
+++ b/test/files/jvm/t3365.check
@@ -0,0 +1,5 @@
+'hello
+'hello
+'hello
+'hello
+'hello
diff --git a/test/files/jvm/t3365.scala b/test/files/jvm/t3365.scala
new file mode 100644
index 0000000000..b94e804e63
--- /dev/null
+++ b/test/files/jvm/t3365.scala
@@ -0,0 +1,65 @@
+import scala.actors.{ReplyReactor, Channel, Actor, Future}
+
+case class ChannelMsg(chan: Channel[Any])
+
+class MyActor extends Actor {
+ def act() {
+ try {
+ val chan = new Channel[Any](this)
+ loop {
+ react {
+ case other: ReplyReactor =>
+ other ! ChannelMsg(chan)
+ loop {
+ chan.react {
+ case 'hello =>
+ reply('hello)
+ case 'stop =>
+ exit()
+ }
+ }
+ }
+ }
+ } catch {
+ case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] =>
+ e.printStackTrace()
+ }
+ }
+}
+
+object Test {
+ def main(args: Array[String]) {
+ val a = new MyActor
+ a.start()
+
+ val b = new Actor {
+ def act() {
+ try {
+ react {
+ case ChannelMsg(c) =>
+ var i = 0
+ loop {
+ i += 1
+ val ft: Future[Any] = c !! 'hello
+ ft.inputChannel.react {
+ case msg =>
+ if (i % 10000 == 0)
+ println(msg)
+ if (i >= 50000) {
+ c ! 'stop
+ exit()
+ }
+ }
+ }
+ }
+ } catch {
+ case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] =>
+ e.printStackTrace()
+ }
+ }
+ }
+ b.start()
+
+ a ! b
+ }
+}
diff --git a/test/files/neg/bug2206.check b/test/files/neg/bug2206.check
new file mode 100644
index 0000000000..3deb4d99ef
--- /dev/null
+++ b/test/files/neg/bug2206.check
@@ -0,0 +1,5 @@
+bug2206.scala:10: error: value f is not a member of o.A
+ Note: implicit method ax is not applicable here because it comes after the application point and it lacks an explicit result type
+ a.f()
+ ^
+one error found
diff --git a/test/files/neg/bug2206.scala b/test/files/neg/bug2206.scala
new file mode 100644
index 0000000000..cd2ec225e9
--- /dev/null
+++ b/test/files/neg/bug2206.scala
@@ -0,0 +1,15 @@
+object o {
+ class A
+
+ class AX {
+ def f() { }
+ }
+
+ import Implicits._
+ val a = new A
+ a.f()
+
+ object Implicits {
+ implicit def ax(a: A) = new AX
+ }
+} \ No newline at end of file
diff --git a/test/files/neg/bug278.check b/test/files/neg/bug278.check
index a3d44f6508..ad0a97371e 100644
--- a/test/files/neg/bug278.check
+++ b/test/files/neg/bug278.check
@@ -1,4 +1,7 @@
-bug278.scala:5: error: overloaded method value a with alternatives => (C.this.A) => Unit <and> => () => Unit does not take type parameters
+bug278.scala:5: error: overloaded method value a with alternatives:
+ => (C.this.A) => Unit <and>
+ => () => Unit
+ does not take type parameters
a[A]
^
bug278.scala:4: error: method a is defined twice
diff --git a/test/files/neg/illegal-stmt-start.check b/test/files/neg/illegal-stmt-start.check
new file mode 100644
index 0000000000..01747524f8
--- /dev/null
+++ b/test/files/neg/illegal-stmt-start.check
@@ -0,0 +1,4 @@
+illegal-stmt-start.scala:3: error: illegal start of statement (no modifiers allowed here)
+ private def bar {}
+ ^
+one error found
diff --git a/test/files/neg/illegal-stmt-start.scala b/test/files/neg/illegal-stmt-start.scala
new file mode 100644
index 0000000000..48ae0a8b0a
--- /dev/null
+++ b/test/files/neg/illegal-stmt-start.scala
@@ -0,0 +1,5 @@
+class Test {
+ def foo {
+ private def bar {}
+ }
+} \ No newline at end of file
diff --git a/test/files/neg/migration28.flags b/test/files/neg/migration28.flags
index f7025d0226..197b3198c8 100644
--- a/test/files/neg/migration28.flags
+++ b/test/files/neg/migration28.flags
@@ -1 +1 @@
--Yfatal-warnings -Xmigration
+-Xfatal-warnings -Xmigration
diff --git a/test/files/neg/names-defaults-neg.check b/test/files/neg/names-defaults-neg.check
index 39347cd5db..644aad4a89 100644
--- a/test/files/neg/names-defaults-neg.check
+++ b/test/files/neg/names-defaults-neg.check
@@ -90,7 +90,7 @@ names-defaults-neg.scala:76: error: no type parameters for method test4: (x: T[T
argument expression's type is not compatible with formal parameter type;
found : List[Int]
required: ?T[ ?T[ scala.List[?T[ X forSome { type X } ]] ] ]
-Error occured in an application involving default arguments.
+Error occurred in an application involving default arguments.
test4()
^
names-defaults-neg.scala:79: error: type mismatch;
@@ -101,7 +101,7 @@ names-defaults-neg.scala:79: error: type mismatch;
names-defaults-neg.scala:82: error: type mismatch;
found : Int
required: String
-Error occured in an application involving default arguments.
+Error occurred in an application involving default arguments.
new A2[String]()
^
24 errors found
diff --git a/test/files/neg/overload-msg.check b/test/files/neg/overload-msg.check
new file mode 100644
index 0000000000..780830bff9
--- /dev/null
+++ b/test/files/neg/overload-msg.check
@@ -0,0 +1,13 @@
+overload-msg.scala:3: error: overloaded method value + with alternatives:
+ (Double)Double <and>
+ (Float)Float <and>
+ (Long)Long <and>
+ (scala.Int)scala.Int <and>
+ (Char)scala.Int <and>
+ (Short)scala.Int <and>
+ (Byte)scala.Int <and>
+ (java.lang.String)java.lang.String
+ cannot be applied to (Int(in method f))
+ def f[Int](y: Int) = x + y
+ ^
+one error found
diff --git a/test/files/neg/overload-msg.scala b/test/files/neg/overload-msg.scala
new file mode 100644
index 0000000000..8715c156a2
--- /dev/null
+++ b/test/files/neg/overload-msg.scala
@@ -0,0 +1,4 @@
+// type parameter shadows actual type, massive overload error confuses.
+class A(x: Int) {
+ def f[Int](y: Int) = x + y
+}
diff --git a/test/files/neg/t3115.flags b/test/files/neg/t3115.flags
index bf8f88334b..d1b831ea87 100644
--- a/test/files/neg/t3115.flags
+++ b/test/files/neg/t3115.flags
@@ -1 +1 @@
--deprecation -Yfatal-warnings \ No newline at end of file
+-deprecation -Xfatal-warnings \ No newline at end of file
diff --git a/test/files/neg/tailrec.check b/test/files/neg/tailrec.check
index 22d70e82a0..27d99f632e 100644
--- a/test/files/neg/tailrec.check
+++ b/test/files/neg/tailrec.check
@@ -1,10 +1,16 @@
-tailrec.scala:6: error: could not optimize @tailrec annotated method
+tailrec.scala:43: error: could not optimize @tailrec annotated method: it contains a recursive call not in tail position
def facfail(n: Int): Int =
^
-tailrec.scala:42: error: could not optimize @tailrec annotated method
+tailrec.scala:50: error: could not optimize @tailrec annotated method: it is neither private nor final so can be overridden
@tailrec def fail1(x: Int): Int = fail1(x)
^
-tailrec.scala:45: error: could not optimize @tailrec annotated method
- @tailrec def fail2[T](xs: List[T]): List[T] = xs match {
- ^
-three errors found
+tailrec.scala:53: error: could not optimize @tailrec annotated method: it contains a recursive call not in tail position
+ @tailrec final def fail2[T](xs: List[T]): List[T] = xs match {
+ ^
+tailrec.scala:59: error: could not optimize @tailrec annotated method: it is called recursively with different type arguments
+ @tailrec final def fail3[T](x: Int): Int = fail3(x - 1)
+ ^
+tailrec.scala:63: error: could not optimize @tailrec annotated method: it changes type of 'this' on a polymorphic recursive call
+ @tailrec final def fail4[U](other: Tom[U], x: Int): Int = other.fail4[U](other, x - 1)
+ ^
+5 errors found
diff --git a/test/files/neg/tailrec.scala b/test/files/neg/tailrec.scala
index 4c45672f93..a77f439cfe 100644
--- a/test/files/neg/tailrec.scala
+++ b/test/files/neg/tailrec.scala
@@ -1,53 +1,65 @@
import scala.annotation.tailrec
// putting @tailrec through the paces
-object Main {
- @tailrec
- def facfail(n: Int): Int =
- if (n == 0) 1
- else n * facfail(n - 1)
-
+object Winners {
@tailrec
def facsucc(n: Int, acc: Int): Int =
if (n == 0) acc
else facsucc(n - 1, n * acc)
- @tailrec def loopy1(x: Int): Int = loopy1(x - 1)
+ @tailrec def loopsucc1(x: Int): Int = loopsucc1(x - 1)
+ @tailrec def loopsucc2[T](x: Int): Int = loopsucc2[T](x - 1)
def ding {
object dong {
- @tailrec def loopy2(x: Int): Int = loopy2(x)
+ @tailrec def loopsucc3(x: Int): Int = loopsucc3(x)
}
()
}
def inner(q: Int) = {
@tailrec
- def loopy3(x: Int): Int = loopy3(x + 1)
+ def loopsucc4(x: Int): Int = loopsucc4(x + 1)
- loopy3(q)
+ loopsucc4(q)
+ }
+
+ object innerBob {
+ @tailrec def loopsucc5(x: Int): Int = loopsucc5(x)
}
}
-class Bob {
- // these should work
+class Winners {
@tailrec private def succ1(x: Int): Int = succ1(x)
@tailrec final def succ2(x: Int): Int = succ2(x)
@tailrec final def succ3[T](in: List[T], acc: List[T]): List[T] = in match {
case Nil => Nil
case x :: xs => succ3(xs, x :: acc)
}
+}
+object Failures {
+ @tailrec
+ def facfail(n: Int): Int =
+ if (n == 0) 1
+ else n * facfail(n - 1)
+}
+
+class Failures {
// not private, not final
@tailrec def fail1(x: Int): Int = fail1(x)
// a typical between-chair-and-keyboard error
- @tailrec def fail2[T](xs: List[T]): List[T] = xs match {
+ @tailrec final def fail2[T](xs: List[T]): List[T] = xs match {
case Nil => Nil
- case x :: xs => x :: fail2(xs)
+ case x :: xs => x :: fail2[T](xs)
}
- object innerBob {
- @tailrec def succ4(x: Int): Int = succ4(x)
+ // unsafe
+ @tailrec final def fail3[T](x: Int): Int = fail3(x - 1)
+
+ // unsafe
+ class Tom[T](x: Int) {
+ @tailrec final def fail4[U](other: Tom[U], x: Int): Int = other.fail4[U](other, x - 1)
}
}
diff --git a/test/files/neg/typeerror.check b/test/files/neg/typeerror.check
index 3e21a79ad5..3ce11dad8a 100644
--- a/test/files/neg/typeerror.check
+++ b/test/files/neg/typeerror.check
@@ -1,6 +1,6 @@
typeerror.scala:6: error: type mismatch;
found : Long(in method add)
- required: Long(in package scala)
+ required: scala.Long
else add2(x.head, y.head) :: add(x.tail, y.tail)
^
one error found
diff --git a/test/files/pos/bug2018.scala b/test/files/pos/bug2018.scala
new file mode 100644
index 0000000000..1736c394c9
--- /dev/null
+++ b/test/files/pos/bug2018.scala
@@ -0,0 +1,15 @@
+class A {
+ val b = new B
+
+ def getChildren = List(new A).iterator
+
+ class B {
+ private def check = true
+
+ private def getAncestor(p: A): A = {
+ val c = (p.getChildren.find(_.b.check)) match {case Some(d) => d case None => p}
+
+ if (c == p) p else c.b.getAncestor(c)
+ }
+ }
+} \ No newline at end of file
diff --git a/test/files/pos/bug3097.flags b/test/files/pos/bug3097.flags
index 570b15929d..144ddac9d3 100644
--- a/test/files/pos/bug3097.flags
+++ b/test/files/pos/bug3097.flags
@@ -1 +1 @@
--unchecked -Yfatal-warnings
+-unchecked -Xfatal-warnings
diff --git a/test/files/pos/bug3278.scala b/test/files/pos/bug3278.scala
new file mode 100644
index 0000000000..788ec75d26
--- /dev/null
+++ b/test/files/pos/bug3278.scala
@@ -0,0 +1,15 @@
+class Foo
+class Test {
+ def update[B](x : B, b : Int) {}
+ def apply[B](x : B) = 1
+}
+
+object Test {
+ def main(a : Array[String]) {
+ val a = new Test
+ val f = new Foo
+ a(f) = 1 //works
+ a(f) = a(f) + 1 //works
+ a(f) += 1 //error: reassignment to val
+ }
+} \ No newline at end of file
diff --git a/test/files/pos/implicits.scala b/test/files/pos/implicits.scala
index 3939a28398..960c265e55 100644
--- a/test/files/pos/implicits.scala
+++ b/test/files/pos/implicits.scala
@@ -82,3 +82,8 @@ package foo2709 {
}
}
}
+
+// Problem with specs
+object specsProblem {
+ println(implicitly[Manifest[Class[_]]])
+}
diff --git a/test/files/pos/spec-traits.scala b/test/files/pos/spec-traits.scala
new file mode 100644
index 0000000000..9e339a14ad
--- /dev/null
+++ b/test/files/pos/spec-traits.scala
@@ -0,0 +1,83 @@
+trait A[@specialized(Int) T] { def foo: T }
+class B extends A[Int] { val foo = 10 }
+class C extends B
+
+// issue 3309
+class Lazy {
+ def test[U](block: => U): Unit = { block }
+
+ test { lazy val x = 1 }
+}
+
+// issue 3307
+class Bug3307 {
+ def f[Z](block: String => Z) {
+ block("abc")
+ }
+
+ ({ () =>
+ f { implicit x => println(x) } })()
+}
+
+// issue 3301
+ trait T[X]
+
+class Bug3301 {
+ def t[A]: T[A] = error("stub")
+
+ () => {
+ type X = Int
+
+ def foo[X] = t[X]
+ ()
+ }
+}
+// issue 3299
+object Failure {
+ def thunk() {
+ for (i <- 1 to 2) {
+ val Array(a, b) = Array(1,2)
+ ()
+ }
+ }
+}
+
+// issue 3296
+
+object AA
+{
+ def f(block: => Unit) {}
+
+ object BB
+ {
+ f {
+ object CC
+
+ ()
+ }
+ }
+
+ def foo[T](x: T) = { object A; false }
+}
+
+// issue 3292
+import scala.swing._
+import scala.swing.GridBagPanel._
+
+object Grid {
+
+ def later(code : => Unit) =
+ javax.swing.SwingUtilities.invokeLater(new Runnable { def run { code }})
+
+ def test = later {
+ val frame = new Dialog {
+ contents = new GridBagPanel {
+ val c = new Constraints
+ }
+ }
+ }
+
+}
+
+// issue 3325
+object O { def f[@specialized T] { for(k <- Nil: List[T]) { } } }
diff --git a/test/files/pos/t3108.scala b/test/files/pos/t3108.scala
new file mode 100644
index 0000000000..6a1da73220
--- /dev/null
+++ b/test/files/pos/t3108.scala
@@ -0,0 +1,5 @@
+object A {
+ val a: NotNull = ""
+ val b: NotNull = 41
+}
+
diff --git a/test/files/pos/t3349/AbstractTupleSet.java b/test/files/pos/t3349/AbstractTupleSet.java
new file mode 100644
index 0000000000..38e4743ef4
--- /dev/null
+++ b/test/files/pos/t3349/AbstractTupleSet.java
@@ -0,0 +1,9 @@
+public abstract class AbstractTupleSet implements TupleSet {
+ public void addColumn(String name, Class type) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void addColumn(String name, String expr) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/test/files/pos/t3349/Table.java b/test/files/pos/t3349/Table.java
new file mode 100644
index 0000000000..1609367623
--- /dev/null
+++ b/test/files/pos/t3349/Table.java
@@ -0,0 +1,9 @@
+public class Table extends AbstractTupleSet {
+ public void addColumn(String name, Class type) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void addColumn(String name, String expr) {
+ throw new UnsupportedOperationException();
+ }
+} \ No newline at end of file
diff --git a/test/files/pos/t3349/Test.scala b/test/files/pos/t3349/Test.scala
new file mode 100644
index 0000000000..8174e4c4f8
--- /dev/null
+++ b/test/files/pos/t3349/Test.scala
@@ -0,0 +1,5 @@
+object Test {
+ val label = "name"
+ val table: Table = error("")
+ table.addColumn( label, label.getClass )
+} \ No newline at end of file
diff --git a/test/files/pos/t3349/TupleSet.java b/test/files/pos/t3349/TupleSet.java
new file mode 100644
index 0000000000..14a073a950
--- /dev/null
+++ b/test/files/pos/t3349/TupleSet.java
@@ -0,0 +1,4 @@
+public interface TupleSet {
+ public void addColumn(String name, Class type);
+ public void addColumn(String name, String expr);
+} \ No newline at end of file
diff --git a/test/files/run/adding-growing-set.scala b/test/files/run/adding-growing-set.scala
new file mode 100644
index 0000000000..5903813ed1
--- /dev/null
+++ b/test/files/run/adding-growing-set.scala
@@ -0,0 +1,11 @@
+/** This will run a a loooong time if Set's builder copies a
+ * complete new Set for every element.
+ */
+object Test {
+ def main(args: Array[String]): Unit = {
+ val a = new Array[Long](1000000)
+ (1 to 10000) foreach (i => a(i) = i)
+ val s = collection.mutable.Set(a: _*)
+ assert(s.sum > 0)
+ }
+}
diff --git a/test/files/run/bug3004.scala b/test/files/run/bug3004.scala
new file mode 100644
index 0000000000..a1e9c6c72f
--- /dev/null
+++ b/test/files/run/bug3004.scala
@@ -0,0 +1,14 @@
+object MyClass {
+ val duplicate: Int = 10
+}
+
+class MyClass {
+ private val duplicate = MyClass.duplicate
+}
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ val x = new MyClass
+ ()
+ }
+}
diff --git a/test/files/run/bug3327.check b/test/files/run/bug3327.check
new file mode 100644
index 0000000000..980a0d5f19
--- /dev/null
+++ b/test/files/run/bug3327.check
@@ -0,0 +1 @@
+Hello World!
diff --git a/test/files/run/bug3327.scala b/test/files/run/bug3327.scala
new file mode 100644
index 0000000000..7e6d3fc210
--- /dev/null
+++ b/test/files/run/bug3327.scala
@@ -0,0 +1,8 @@
+object Test {
+ def main (args : Array[String]) {
+ val b = new StringBuilder
+ b.append ("Hello World!")
+ b.lastIndexOf ('e')
+ println (b.toString)
+ }
+} \ No newline at end of file
diff --git a/test/files/run/distinct.check b/test/files/run/distinct.check
new file mode 100644
index 0000000000..b0883f382e
--- /dev/null
+++ b/test/files/run/distinct.check
@@ -0,0 +1 @@
+abcdefghijklmnopqrstuvwxyz
diff --git a/test/files/run/distinct.scala b/test/files/run/distinct.scala
new file mode 100644
index 0000000000..698d31f1e9
--- /dev/null
+++ b/test/files/run/distinct.scala
@@ -0,0 +1,15 @@
+/** This is a test to make sure distinct always
+ * returns the first of any duplicated element.
+ */
+object Test {
+ val alphabet = 'a' to 'z' mkString ""
+ val alphaList = 'a' to 'z' toList
+ def shuffled = util.Random.shuffle(alphaList)
+
+ def main(args: Array[String]): Unit = {
+ val longList = alphaList ++ (1 to 9 flatMap (_ => shuffled))
+ val result = longList.distinct mkString ""
+
+ println(result)
+ }
+}
diff --git a/test/files/run/iterator-iterate-lazy.scala b/test/files/run/iterator-iterate-lazy.scala
new file mode 100644
index 0000000000..73886f192b
--- /dev/null
+++ b/test/files/run/iterator-iterate-lazy.scala
@@ -0,0 +1,5 @@
+object Test {
+ def main(args: Array[String]): Unit = {
+ Iterator.iterate(1 to 5 toList)(_.tail).takeWhile(_.nonEmpty).map(_.head).toList
+ }
+}
diff --git a/test/files/run/mapValues.scala b/test/files/run/mapValues.scala
new file mode 100644
index 0000000000..d3266bd18f
--- /dev/null
+++ b/test/files/run/mapValues.scala
@@ -0,0 +1,8 @@
+object Test {
+ val m = Map(1 -> 1, 2 -> 2)
+ val mv = (m mapValues identity) - 1
+
+ def main(args: Array[String]): Unit = {
+ assert(mv.size == 1)
+ }
+}
diff --git a/test/files/run/names-defaults.scala b/test/files/run/names-defaults.scala
index 3442ecafc3..ee9186c35f 100644
--- a/test/files/run/names-defaults.scala
+++ b/test/files/run/names-defaults.scala
@@ -324,6 +324,27 @@ object Test extends Application {
}
}
+ // #3344
+ def m3344_1 = { case class C(x: Int); C(1).copy(2).x }
+ m3344_1
+ def m3344_2 = { class C(val x: Int = 1); new C().x }
+ m3344_2
+
+ // #3338
+ object t3338 {
+ class Container {
+ class GenericClass[T](arg: String = "")
+ }
+
+ object Container extends Container
+
+ class Test {
+ val a = new Container.GenericClass()
+ }
+ }
+ (new t3338.Test).a
+
+
// DEFINITIONS
def test1(a: Int, b: String) = println(a +": "+ b)
diff --git a/test/files/run/spec-early.check b/test/files/run/spec-early.check
new file mode 100644
index 0000000000..414aacc419
--- /dev/null
+++ b/test/files/run/spec-early.check
@@ -0,0 +1,4 @@
+a
+abc
+42
+abc
diff --git a/test/files/run/spec-early.scala b/test/files/run/spec-early.scala
new file mode 100644
index 0000000000..84a8983f8c
--- /dev/null
+++ b/test/files/run/spec-early.scala
@@ -0,0 +1,15 @@
+trait Tr
+
+class Foo[@specialized(Int) T](_x: T) extends {
+ val bar = "abc"
+ val baz = "bbc"
+} with Tr {
+ val x = _x
+ println(x)
+ println(bar)
+}
+
+object Test extends Application {
+ new Foo("a")
+ new Foo(42)
+}
diff --git a/test/files/run/spec-init.check b/test/files/run/spec-init.check
new file mode 100644
index 0000000000..8a659f868c
--- /dev/null
+++ b/test/files/run/spec-init.check
@@ -0,0 +1,9 @@
+abc
+abc
+null
+shouldn't see two initialized values and one uninitialized
+42
+42
+0
+ok
+ok
diff --git a/test/files/run/spec-init.scala b/test/files/run/spec-init.scala
new file mode 100644
index 0000000000..bd3428f4ea
--- /dev/null
+++ b/test/files/run/spec-init.scala
@@ -0,0 +1,41 @@
+class Foo[@specialized(Int) T](_x: T) {
+ val x = _x
+ def bar {}
+
+ val y = x
+ println(x)
+ println(y)
+ println(z)
+
+ def baz {}
+ val z = y
+
+}
+
+class Bar[@specialized(Int) T] {
+ def foo(x: T) = print(x)
+}
+
+object Global {
+ var msg = "ok"
+}
+
+class TouchGlobal[@specialized(Int) T](_x: T) {
+ println(Global.msg)
+ val x = {
+ Global.msg = "not ok"
+ _x
+ }
+}
+
+object Test {
+ def main(args: Array[String]) {
+ (new Foo("abc"))
+ println("shouldn't see two initialized values and one uninitialized")
+ (new Foo(42))
+
+ (new TouchGlobal(new Object))
+ Global.msg = "ok" // reset the value
+ (new TouchGlobal(42))
+ }
+}
diff --git a/test/files/run/stream_length.scala b/test/files/run/stream_length.scala
new file mode 100644
index 0000000000..68e9cad5ac
--- /dev/null
+++ b/test/files/run/stream_length.scala
@@ -0,0 +1,15 @@
+
+
+object Test {
+ def walk(depth: Int, bias: String): Stream[String] = {
+ if (depth == 0)
+ Stream(bias)
+ else {
+ Stream.concat(Stream.range(1, 100).map((x: Int) => walk(depth-1, bias + x)))
+ }
+ }
+
+ def main(args: Array[String]) {
+ println("Length: " + walk(3, "---").length)
+ }
+}
diff --git a/test/files/run/stringbuilder.scala b/test/files/run/stringbuilder.scala
index c669f1c3db..28ddc653a5 100644
--- a/test/files/run/stringbuilder.scala
+++ b/test/files/run/stringbuilder.scala
@@ -1,5 +1,7 @@
object Test extends Application {
val str = "ABCDEFGHIJKLMABCDEFGHIJKLM"
+ val surrogateStr = "an old Turkic letter: \uD803\uDC22"
+
type SB = {
def indexOf(str: String): Int
def indexOf(str: String, fromIndex: Int): Int
@@ -29,4 +31,10 @@ object Test extends Application {
sameAnswers(_.lastIndexOf("QZV"))
sameAnswers(_.lastIndexOf("GHI", 22))
sameAnswers(_.lastIndexOf("KLM", 22))
+
+ // testing that the "reverse" implementation avoids reversing surrogate pairs
+ val jsb = new JavaStringBuilder(surrogateStr) reverse
+ val ssb = new ScalaStringBuilder(surrogateStr) reverseContents ;
+
+ assert(jsb.toString == ssb.toString)
}
diff --git a/test/files/run/treePrint.scala b/test/files/run/treePrint.scala
index ffe9a392d4..1fd1394e25 100644
--- a/test/files/run/treePrint.scala
+++ b/test/files/run/treePrint.scala
@@ -35,6 +35,6 @@ object Test {
val repl = new Interpreter(settings, new PrintWriter(new NullOutputStream))
repl.interpret("""def initialize = "Have to interpret something or we get errors." """)
- println(repl mkTree code)
+ println(repl.power mkTree code)
}
}
diff --git a/test/pending/run/string-reverse.scala b/test/pending/run/string-reverse.scala
new file mode 100644
index 0000000000..51b16bcd6a
--- /dev/null
+++ b/test/pending/run/string-reverse.scala
@@ -0,0 +1,22 @@
+/** In case we ever feel like taking on unicode string reversal.
+ * See ticket #2565.
+ */
+object Test {
+ val xs = "Les Mise\u0301rables" // this is the tricky one to reverse
+ val ys = "Les Misérables"
+ val xs2 = new StringBuilder(xs)
+ val ys2 = new StringBuilder(ys)
+
+ def main(args: Array[String]): Unit = {
+ val out = new java.io.PrintStream(System.out, true, "UTF-8")
+
+ out.println("Strings")
+ List(xs, xs.reverse, ys, ys.reverse) foreach (out println _)
+
+ out.println("StringBuilder")
+ out.println(xs2.toString)
+ out.println(xs2.reverseContents().toString)
+ out.println(ys2.toString)
+ out.println(ys2.reverseContents().toString)
+ }
+} \ No newline at end of file
diff --git a/tools/scmp b/tools/scmp
new file mode 100755
index 0000000000..f6acea5ab1
--- /dev/null
+++ b/tools/scmp
@@ -0,0 +1,4 @@
+#!/bin/sh
+#
+
+scala scala.tools.cmd.program.Scmp "$@"
diff --git a/tools/tokens b/tools/tokens
new file mode 100755
index 0000000000..b910fb29cc
--- /dev/null
+++ b/tools/tokens
@@ -0,0 +1,4 @@
+#!/bin/sh
+#
+
+scala scala.tools.cmd.program.Tokens "$@"