summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTING.md28
-rw-r--r--README.md380
-rw-r--r--build.sbt12
-rw-r--r--build.xml2
-rw-r--r--project/Quiet.scala33
-rw-r--r--project/plugins.sbt2
-rw-r--r--spec/02-identifiers-names-and-scopes.md91
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala3
-rw-r--r--src/compiler/scala/tools/nsc/classpath/AggregateClassPath.scala12
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala12
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala21
-rw-r--r--src/compiler/scala/tools/nsc/transform/TypeAdaptingTransformer.scala22
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala10
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala65
-rw-r--r--src/intellij/README.md64
-rw-r--r--src/library/scala/Console.scala146
-rw-r--r--src/library/scala/collection/immutable/ListMap.scala282
-rw-r--r--src/library/scala/collection/immutable/ListSet.scala217
-rw-r--r--src/library/scala/collection/immutable/Range.scala2
-rw-r--r--src/library/scala/collection/immutable/StringLike.scala16
-rw-r--r--src/library/scala/io/AnsiColor.scala155
-rw-r--r--src/library/scala/runtime/java8/JFunction0.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction1.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction10.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction11.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction12.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction13.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction14.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction15.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction16.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction17.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction18.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction19.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction2.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction20.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction21.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction22.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction3.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction4.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction5.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction6.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction7.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction8.java2
-rw-r--r--src/library/scala/runtime/java8/JFunction9.java2
-rw-r--r--src/repl/scala/tools/nsc/interpreter/IMain.scala203
-rw-r--r--src/repl/scala/tools/nsc/interpreter/Imports.scala35
-rw-r--r--src/repl/scala/tools/nsc/interpreter/Scripted.scala343
-rw-r--r--src/repl/scala/tools/nsc/interpreter/package.scala23
-rw-r--r--src/scaladoc/scala/tools/ant/Scaladoc.scala4
-rw-r--r--src/scaladoc/scala/tools/nsc/ScalaDoc.scala51
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/DocFactory.scala16
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/Doclet.scala13
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala5
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala3
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/page/Entity.scala12
-rw-r--r--test/files/jvm/interpreter.check2
-rw-r--r--test/files/jvm/serialization-new.check8
-rw-r--r--test/files/jvm/serialization.check8
-rw-r--r--test/files/neg/constrs.check2
-rw-r--r--test/files/neg/t4460a.check2
-rw-r--r--test/files/neg/t4460b.check2
-rw-r--r--test/files/neg/t9045.check7
-rw-r--r--test/files/neg/t9045.scala8
-rw-r--r--test/files/neg/t9361.check11
-rw-r--r--test/files/neg/t9361.scala5
-rw-r--r--test/files/pos/t5183.scala34
-rw-r--r--test/files/pos/t7088.scala8
-rw-r--r--test/files/pos/t9665.scala7
-rw-r--r--test/files/run/repl-classbased.check23
-rw-r--r--test/files/run/repl-classbased.scala22
-rw-r--r--test/files/run/repl-implicits-nopredef.check5
-rw-r--r--test/files/run/repl-implicits-nopredef.scala10
-rw-r--r--test/files/run/repl-implicits.check5
-rw-r--r--test/files/run/repl-implicits.scala5
-rw-r--r--test/files/run/repl-serialization.scala2
-rw-r--r--test/files/run/t1500.scala2
-rw-r--r--test/files/run/t3822.scala19
-rw-r--r--test/files/run/t5463.scala21
-rw-r--r--test/files/run/t6198.scala7
-rw-r--r--test/files/run/t7319.check6
-rw-r--r--test/files/run/t7445.scala6
-rw-r--r--test/files/run/t7843-jsr223-service.check2
-rw-r--r--test/files/run/t7843-jsr223-service.scala8
-rw-r--r--test/files/run/t7933.check2
-rw-r--r--test/files/run/t7933.scala11
-rw-r--r--test/files/run/t8549.scala4
-rw-r--r--test/files/run/t8756.check9
-rw-r--r--test/files/run/t8756.scala22
-rw-r--r--test/files/run/trait-static-forwarder.check1
-rw-r--r--test/files/run/trait-static-forwarder/Test.java5
-rw-r--r--test/files/run/trait-static-forwarder/forwarders.scala5
-rw-r--r--test/junit/scala/BoxUnboxTest.scala119
-rw-r--r--test/junit/scala/PartialFunctionSerializationTest.scala16
-rw-r--r--test/junit/scala/collection/convert/NullSafetyTest.scala279
-rw-r--r--test/junit/scala/collection/convert/NullSafetyToJavaTest.scala138
-rw-r--r--test/junit/scala/collection/convert/NullSafetyToScalaTest.scala148
-rw-r--r--test/junit/scala/collection/immutable/ListMapTest.scala48
-rw-r--r--test/junit/scala/collection/immutable/ListSetTest.scala53
-rw-r--r--test/junit/scala/issues/BytecodeTest.scala478
-rw-r--r--test/junit/scala/lang/annotations/BytecodeTest.scala80
-rw-r--r--test/junit/scala/lang/annotations/RunTest.scala32
-rw-r--r--test/junit/scala/lang/primitives/BoxUnboxTest.scala249
-rw-r--r--test/junit/scala/lang/primitives/PredefAutoboxingTest.scala (renamed from test/junit/scala/PredefAutoboxingTest.scala)6
-rw-r--r--test/junit/scala/lang/stringinterpol/StringContextTest.scala (renamed from test/junit/scala/StringContextTest.scala)9
-rw-r--r--test/junit/scala/lang/traits/BytecodeTest.scala282
-rw-r--r--test/junit/scala/lang/traits/RunTest.scala20
-rw-r--r--test/junit/scala/reflect/ClassOfTest.scala (renamed from test/junit/scala/issues/RunTest.scala)58
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala40
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala171
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/DefaultMethodTest.scala23
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala41
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala33
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/IndySammyTest.scala42
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/OptimizedBytecodeTest.scala (renamed from test/junit/scala/issues/OptimizedBytecodeTest.scala)103
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala28
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala58
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerTest.scala92
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/AnalyzerTest.scala39
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala32
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala64
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala58
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/CompactLocalVariablesTest.scala22
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala37
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/EmptyLabelsAndLineNumbersTest.scala12
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala47
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala64
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala34
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerSeparateCompilationTest.scala31
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala345
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala185
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala31
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala10
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala72
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/UnusedLocalVariablesTest.scala41
-rw-r--r--test/junit/scala/tools/nsc/interpreter/ScriptedTest.scala83
-rw-r--r--test/junit/scala/tools/nsc/transform/delambdafy/DelambdafyTest.scala16
-rw-r--r--test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala77
-rw-r--r--test/junit/scala/tools/testing/BytecodeTesting.scala (renamed from test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala)243
-rw-r--r--test/junit/scala/tools/testing/ClearAfterClass.java47
-rw-r--r--test/junit/scala/tools/testing/RunTesting.scala17
142 files changed, 3927 insertions, 2967 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 617734210f..47d2788623 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -8,7 +8,7 @@ In 2014, you -- the Scala community -- matched the core team at EPFL in number o
We are super happy about this, and are eager to make your experience contributing to Scala productive and satisfying, so that we can keep up this growth. We can't do this alone (nor do we want to)!
-This is why we're collecting these notes on how to contribute, and we hope you'll share your experience to improve the process for the next contributor! (Feel free to send a PR for this note, send your thoughts to scala-internals, or tweet about it to @adriaanm.)
+This is why we're collecting these notes on how to contribute, and we hope you'll share your experience to improve the process for the next contributor! (Feel free to send a PR for this note, send your thoughts to gitter, scala-internals, or tweet about it to @adriaanm.)
By the way, the team at Lightbend is: @adriaanm, @lrytz, @retronym, @SethTisue, and @szeiger.
@@ -117,14 +117,32 @@ See the [scala-jenkins-infra repo](https://github.com/scala/scala-jenkins-infra)
### Pass code review
-Your PR will need to be assigned to one or more reviewers. You can suggest reviewers yourself; if you're not sure, see the list in [README.md](README.md) or ask on scala-internals.
+Your PR will need to be assigned to one or more reviewers. You can suggest reviewers
+yourself; if you're not sure, see the list in [README.md](README.md) or ask on gitter
+or scala-internals.
-To assign a reviewer, add a "review by @reviewer" to your PR description.
+To assign a reviewer, add a "review by @reviewer" to the PR description or in a
+comment on your PR.
NOTE: it's best not to @mention in commit messages, as github pings you every time a commit with your @name on it shuffles through the system (even in other repos, on merges,...).
A reviewer gives the green light by commenting "LGTM" (looks good to me).
-A review feedback may be addressed by pushing new commits to the request, if these commits stand on their own.
+When including review feedback, we typically amend the changes into the existing commit(s)
+and `push -f` to the branch. This is to keep the git history clean. Additional commits
+are OK if they stand on their own.
-Once all these conditions are met, and we agree with the change (we are available on scala-internals to discuss this beforehand, before you put in the coding work!), we will merge your changes.
+Once all these conditions are met, and we agree with the change (we are available on
+gitter or scala-internals to discuss this beforehand, before you put in the coding work!),
+we will merge your changes.
+
+We use the following labels:
+
+Label | Description
+-------------------------|:-----------
+`reviewed` | automatically added by scabot when a comment prefixed with LGTM is posted
+`welcome` | added by reviewer / queue curator to welcome someone's first PR (for highlighting in the release notes)
+`release-notes` | added by reviewer / queue curator to make sure this PR is highlighted in the release notes
+`on-hold` | added when this PR should not yet be merged, even though CI is green
+`WIP` | added by the author if a PR is submitted for CI testing, needs more work to be complete
+`assistance-appreciated` | added by the author if help by the community is appreciated to move a change forward
diff --git a/README.md b/README.md
index dc869da0da..6ebb453176 100644
--- a/README.md
+++ b/README.md
@@ -5,12 +5,12 @@ This is the official repository for the [Scala Programming Language](http://www.
To contribute to the Scala Standard Library, Scala Compiler and Scala Language Specification, please send us a [pull request](https://help.github.com/articles/using-pull-requests/#fork--pull) from your fork of this repository! We do have to ask you to sign the [Scala CLA](http://www.lightbend.com/contribute/cla/scala) before we can merge any of your work into our code base, to protect its open source nature.
-For more information on building and developing the core of Scala, read on!
+For more information on building and developing the core of Scala, make sure to read
+the rest of this README!
-Please also check out:
-
-* our [guidelines for contributing](CONTRIBUTING.md).
-* the ["Scala Hacker Guide"](http://scala-lang.org/contribute/hacker-guide.html) covers some of the same ground as this README, but in greater detail and in a more tutorial style, using a running example.
+In order to get in touch with Scala contributors, join the
+[scala/contributors](https://gitter.im/scala/contributors) gitter channel or post on the
+[scala-internals mailing list](http://www.scala-lang.org/community/).
# Reporting issues
@@ -18,195 +18,247 @@ We're still using Jira for issue reporting, so please [report any issues](https:
(We would love to start using GitHub Issues, but we're too resource-constrained to take on this migration right now.)
# Get in touch!
-If you need some help with your PR at any time, please feel free to @-mention anyone from the list below (or simply `@scala/team-core-scala`), and we will do our best to help you out:
+If you need some help with your PR at any time, please feel free to @-mention anyone from the list below, and we will do our best to help you out:
| username | talk to me about... |
--------------------------------------------------------------------------------------------------|----------------------------------------------------------------|---------------------------------------------------|
- <img src="https://avatars.githubusercontent.com/adriaanm" height="50px" title="Adriaan Moors"/> | [`@adriaanm`](https://github.com/adriaanm) | type checker, pattern matcher, infrastructure, language spec |
- <img src="https://avatars.githubusercontent.com/SethTisue" height="50px" title="Seth Tisue"/> | [`@SethTisue`](https://github.com/SethTisue) | build, developer docs, community build, Jenkins, library, the welcome-to-Scala experience |
- <img src="https://avatars.githubusercontent.com/retronym" height="50px" title="Jason Zaugg"/> | [`@retronym`](https://github.com/retronym) | compiler performance, weird compiler bugs, Java 8 lambdas, REPL |
- <img src="https://avatars.githubusercontent.com/Ichoran" height="50px" title="Rex Kerr"/> | [`@Ichoran`](https://github.com/Ichoran) | collections library, performance |
- <img src="https://avatars.githubusercontent.com/lrytz" height="50px" title="Lukas Rytz"/> | [`@lrytz`](https://github.com/lrytz) | optimizer, named & default arguments |
- <img src="https://avatars.githubusercontent.com/VladUreche" height="50px" title="Vlad Ureche"/> | [`@VladUreche`](https://github.com/VladUreche) | specialization, Scaladoc tool |
- <img src="https://avatars.githubusercontent.com/densh" height="50px" title="Denys Shabalin"/> | [`@densh`](https://github.com/densh) | quasiquotes, parser, string interpolators, macros in standard library |
- <img src="https://avatars.githubusercontent.com/xeno-by" height="50px" title="Eugene Burmako"/> | [`@xeno-by`](https://github.com/xeno-by) | macros and reflection |
- <img src="https://avatars.githubusercontent.com/heathermiller" height="50px" title="Heather Miller"/> | [`@heathermiller`](https://github.com/heathermiller) | documentation |
- <img src="https://avatars.githubusercontent.com/dickwall" height="50px" title="Dick Wall"/> | [`@dickwall`](https://github.com/dickwall) | process & community, documentation |
- <img src="https://avatars.githubusercontent.com/dragos" height="50px" title="Iulian Dragos"/> | [`@dragos`](https://github.com/dragos) | specialization, back end |
- <img src="https://avatars.githubusercontent.com/axel22" height="50px" title="Aleksandr Prokopec"/> | [`@axel22`](https://github.com/axel22) | collections, concurrency, specialization |
- <img src="https://avatars.githubusercontent.com/janekdb" height="50px" title="Janek Bogucki"/> | [`@janekdb`](https://github.com/janekdb) | documentation |
+ <img src="https://avatars.githubusercontent.com/adriaanm" height="50px" title="Adriaan Moors"/> | [`@adriaanm`](https://github.com/adriaanm) | type checker, pattern matcher, infrastructure, language spec |
+ <img src="https://avatars.githubusercontent.com/SethTisue" height="50px" title="Seth Tisue"/> | [`@SethTisue`](https://github.com/SethTisue) | build, developer docs, community build, Jenkins, library, the welcome-to-Scala experience |
+ <img src="https://avatars.githubusercontent.com/retronym" height="50px" title="Jason Zaugg"/> | [`@retronym`](https://github.com/retronym) | compiler performance, weird compiler bugs, Java 8 lambdas, REPL |
+ <img src="https://avatars.githubusercontent.com/Ichoran" height="50px" title="Rex Kerr"/> | [`@Ichoran`](https://github.com/Ichoran) | collections library, performance |
+ <img src="https://avatars.githubusercontent.com/lrytz" height="50px" title="Lukas Rytz"/> | [`@lrytz`](https://github.com/lrytz) | optimizer, named & default arguments |
+ <img src="https://avatars.githubusercontent.com/VladUreche" height="50px" title="Vlad Ureche"/> | [`@VladUreche`](https://github.com/VladUreche) | specialization, Scaladoc tool |
+ <img src="https://avatars.githubusercontent.com/densh" height="50px" title="Denys Shabalin"/> | [`@densh`](https://github.com/densh) | quasiquotes, parser, string interpolators, macros in standard library |
+ <img src="https://avatars.githubusercontent.com/xeno-by" height="50px" title="Eugene Burmako"/> | [`@xeno-by`](https://github.com/xeno-by) | macros and reflection |
+ <img src="https://avatars.githubusercontent.com/heathermiller" height="50px" title="Heather Miller"/> | [`@heathermiller`](https://github.com/heathermiller) | documentation |
+ <img src="https://avatars.githubusercontent.com/dickwall" height="50px" title="Dick Wall"/> | [`@dickwall`](https://github.com/dickwall) | process & community, documentation |
+ <img src="https://avatars.githubusercontent.com/dragos" height="50px" title="Iulian Dragos"/> | [`@dragos`](https://github.com/dragos) | specialization, back end |
+ <img src="https://avatars.githubusercontent.com/axel22" height="50px" title="Aleksandr Prokopec"/> | [`@axel22`](https://github.com/axel22) | collections, concurrency, specialization |
+ <img src="https://avatars.githubusercontent.com/janekdb" height="50px" title="Janek Bogucki"/> | [`@janekdb`](https://github.com/janekdb) | documentation |
P.S.: If you have some spare time to help out around here, we would be delighted to add your name to this list!
-# Handy Links
- - [A wealth of documentation](http://docs.scala-lang.org)
- - [mailing lists](http://www.scala-lang.org/community/)
- - [Gitter room for Scala contributors](https://gitter.im/scala/contributors)
- - [Scala CI](https://scala-ci.typesafe.com/)
- - download the latest nightlies:
- - [2.11.x](http://www.scala-lang.org/files/archive/nightly/2.11.x/)
- - [2.12.x](http://www.scala-lang.org/files/archive/nightly/2.12.x/)
-
# Repository structure
```
scala/
-+--build.xml The main Ant build script, see also under src/build.
-+--pull-binary-libs.sh Pulls binary artifacts from remote repository.
-+--lib/ Pre-compiled libraries for the build.
-+--src/ All sources.
- +---/library Scala Standard Library.
- +---/reflect Scala Reflection.
- +---/compiler Scala Compiler.
- +---/eclipse Eclipse project files.
- +---/intellij IntelliJ project templates.
++--build.sbt The main sbt build script
++--build.xml The deprecated Ant build script
++--pull-binary-libs.sh Pulls binary artifacts from remote repository, used by build scripts
++--lib/ Pre-compiled libraries for the build
++--src/ All sources
+ +---/library Scala Standard Library
+ +---/reflect Scala Reflection
+ +---/compiler Scala Compiler
+ +---/eclipse Eclipse project files
+ +---/intellij IntelliJ project templates
++--spec/ The Scala language specification
+--scripts/ Scripts for the CI jobs (including building releases)
-+--test/ The Scala test suite.
-+--build/ [Generated] Build products output directory for ant.
-+--dist/ [Generated] The destination folder for Scala distributions.
++--test/ The Scala test suite
+ +---/files Partest tests
+ +---/junit JUnit tests
++--build/ [Generated] Build output directory
```
-# How we roll
+# Get Ready to Contribute
## Requirements
-You'll need a Java SDK. The baseline version is 6 for 2.11.x, 8 for
-2.12.x. (It's also possible to use a later SDK for local development,
-but the CI will verify against the baseline version.)
-
-You'll also need Apache Ant (version 1.9.3 or above) and curl (for `./pull-binary-libs.sh`).
-
-Mac OS X and Linux work. Windows may work if you use Cygwin. (Community help with keeping the build working on Windows is appreciated.)
-
-## Git Hygiene
-
-As git history is forever, we take great pride in the quality of the commits we merge into the repository. The title of your commit will be read hundreds (of thousands? :-)) of times, so it pays off to spend just a little bit more time to polish it, making it descriptive and concise. Please take a minute to read the advice [most projects agree on](https://github.com/erlang/otp/wiki/Writing-good-commit-messages), and stick to 72 or fewer characters for the first line, wrapping subsequent ones at 80 (at most).
-
-When not sure how to formulate your commit message, imagine you're writing a bullet item for the next release notes, or describing what the commit does to the code base (use active verbs in the present tense). When your commit title is featured in the next release notes, it will be read by a lot of curious Scala users, looking for the latest improvements. Satisfy their thirst for information with as few words as possible! Also, a commit should convey clearly to your (future) fellow contributors what it does to the code base.
-
-Writing the commit message is a great sanity check that the commit is of the right size. If it does too many things, the description will be unwieldy and tedious to write. Chop it up (`git add -u --patch` and `git rebase` are your friends) and simplify!
-
-To pinpoint bugs, we often use git bisect, which is only effective when we can count on each commit building (and passing the test suite). Thus, the CI bot enforces this. Please rebase your development history into a sensible list of self-contained commits that tell the story of your bug fix or improvement. Carve them up so that the riskier bits can be reverted independently. Keep changes focussed by splitting out cleanups from refactorings from actual changes to the logic.
-
-This facilitates reviewing: a commit that reformats code can be judged quickly not to affect anything, so we can focus on the meat of the PR. It also helps when merging between long-running branches, reducing conflicts (or providing at least a limited scope for each one).
-
-Please do not @-mention anyone in the commit message -- that's what the PR description and comments are for. Every time a commit is shuffled through github (in a merge in some fork, say), every @-mention results in an email to that person (the core team treats them as personal email, straight to their inbox, so please don't flood us :-)).
-
-
-## Reviews
-
-Please consider nominating a reviewer for your PR in the PR's description or a comment. If unsure, not to worry -- the core team will assign one for you.
-
-Your reviewer is also your mentor, who will help you rework your PR so that it meets our requirements. We strive to give timely feedback, and apologize for those times when we are overwhelmed by the volume of contributions. Please feel free to ping us. You are entitled to regular progress updates and at least a quick assessment of feasibility of a bigger PR.
-
-To help you plan your contributions, we communicate our plans on a regular basis on scala-internals, and deadlines are tracked as due dates for [GitHub milestones](https://github.com/scala/scala/milestones).
-
-## Reviewing
-
-Once you've gained some experience with the code base and the process, the next step is to review the contributions of others.
-
-The main goal of this whole process is to ensure the health of the Scala project by improving the quality of the code base, the documentation, as well as this process itself. Thank you for doing your part!
-
-## [Labels](https://github.com/scala/scala/labels)
-
-Label | Description
---------------- | -----------
-`reviewed` | automatically added by scabot when a comment prefixed with LGTM is posted
-`welcome` | reviewer / queue curator adds to welcome someone's first PR (for highlighting in the release notes)
-`release-notes` | reviewer / queue curator adds to make sure this PR is highlighted in the release notes
-`on-hold` | added when this PR should not yet be merged, even though CI is green
-
-### Tips & Tricks
-Once the `publish-core` task has completed on a commit, you can try it out in sbt as follows:
+You need the following tools:
+ - A Java SDK. The baseline version is 6 for 2.11.x, 8 for 2.12.x. It's possible
+ to use a later SDK for local development, but the CI will verify against the baseline
+ version.
+ - sbt, we recommend the [sbt-extras](https://github.com/paulp/sbt-extras) runner
+ script. It provides sensible default jvm options (stack and heap size).
+ - curl (for `./pull-binary-libs.sh`, used by the sbt / ant build).
+ - Apache Ant (version 1.9.3 or above) if you need to use the (deprecated) ant build.
+
+Mac OS X and Linux work. Windows may work if you use Cygwin. Community help with keeping
+the build working on Windows is appreciated.
+
+## Build Setup
+
+### Basics
+
+Scala is built in layers, where each layer is a complete Scala compiler and library.
+Here is a short description of the layers, from bottom to top:
+
+ - `starr`: the stable reference Scala release. We use an official release of
+ Scala (specified by `starr.version` in [versions.properties](versions.properties)),
+ downloaded from the Central Repository.
+ - `locker` (deprecated, only in ant): an intermediate layer that existed in the
+ ant build to perform a bootstrap.
+ - `quick`: the development layer which is incrementally built when working on
+ changes in the compiler or library.
+ - `strap` (deprecated, only in ant) : a test layer used to check stability of
+ the build.
+
+The sbt build uses `starr` to build `quick`. This is sufficient for most development
+scenarios: changes to the library or the compiler can be tested by running the `quick`
+Scala (see below for how to do that).
+
+However, a full build of Scala (a *bootstrap*, as performed by our CI) requires two
+layers. This guarantees that every Scala version can build itself. If you change the
+code generation part of the Scala compiler, your changes will only reflect in the
+bytecode of the library and compiler after a bootstrap. See below for how to create
+a bootstrap build locally.
+
+### Using the Sbt Build
+
+Core commands:
+ - `compile` compiles all sub-projects (library, reflect, compiler, scaladoc, etc)
+ - `scala` / `scalac` run the REPL / compiler directly from sbt (accept options /
+ arguments)
+ - `dist/mkBin` generates runner scripts (`scala`, `scalac`, etc) in `build/quick/bin`
+ - `dist/mkPack` creates a build in the Scala distribution format in `build/pack`
+ - `test` runs the JUnit test, `testOnly *immutable.ListTest` runs a subset
+ - `partest` runs partest tests (accepts options, try `partest --help`)
+ - `publishLocal` publishes a distribution locally (can be used as `scalaVersion` in
+ other sbt projects)
+ - Optionally `set VersionUtil.baseVersionSuffix in Global := "abcd123-SNAPSHOT"`
+ where `abcd123` is the git hash of the revision being published. You can also
+ use something custom like `"mypatch"`. This changes the version number from
+ `2.12.0-SNAPSHOT` to something more stable (`2.12.0-abcd123-SNAPSHOT`).
+ - Optionally `set publishArtifact in (Compile, packageDoc) in ThisBuild := false`
+ to skip generating / publishing API docs (speeds up the process).
+
+#### Sandbox
+
+We recommend to keep local test files in the `sandbox` directory which is listed in
+the `.gitignore` of the Scala repo.
+
+#### Incremental Compilation
+
+Note that sbt's incremental compilation is often too coarse for the Scala compiler
+codebase and re-compiles too many files, resulting in long build times (check
+[sbt#1104](https://github.com/sbt/sbt/issues/1104) for progress on that front). In the
+meantime you can:
+ - Enable "ant mode" in which sbt only re-compiles source files that were modified.
+ Create a file `local.sbt` containing the line `(incOptions in ThisBuild) := (incOptions in ThisBuild).value.withNameHashing(false).withAntStyle(true)`.
+ Add an entry `local.sbt` to your `~/.gitignore`.
+ - Use IntelliJ IDEA for incremental compiles (see [IDE Setup](#ide-setup) below) - its
+ incremental compiler is a bit less conservative, but usually correct.
+
+#### Local Bootstrap Build
+
+To perform a bootstrap using sbt
+ - first a build is published either locally or on a temporary repository,
+ - then a separate invocation of sbt (using the previously built version as `starr`)
+ is used to build / publish the actual build.
+
+Assume the current `starr` version is `2.12.0-M4` (defined in
+[versions.properties](versions.properties)) and the current version is `2.12.0-SNAPSHOT`
+(defined in [build.sbt](build.sbt)). To perform a local bootstrap:
+ - Run `publishLocal` (you may want to specify a custom version suffix and skip
+ generating API docs, see above).
+ - Quit sbt and start a new sbt instance using `sbt -Dstarr.version=<version>` where
+ `<version>` is the version number you published locally.
+ - If the version number you published is not binary compatible with the current
+ `starr`, `set every scalaBinaryVersion := "2.12.0-M4"`. This is not required if
+ the version you published locally is binary compatible, i.e., if the current
+ `starr` is a 2.12.x release and not a milestone / RC.
+
+The last step is required to resolve modules (scala-xml, scala-partest, etc). It
+assumes that the module releases for the current `starr` work (in terms of binary
+compatibility) with the local starr that you published locally. A full bootstrap
+requires re-building the all the modules. On our CI this is handled by the
+[bootstrap](scripts/jobs/integrate/bootstrap) script, but it (currently) cannot
+be easily executed locally.
+
+### IDE Setup
+
+You may use IntelliJ IDEA ([src/intellij/README.md](src/intellij/README.md)) or the
+Scala IDE for Eclipse (see [src/eclipse/README.md](src/eclipse/README.md)).
+
+In order to use IntelliJ's incremental compiler:
+ - run `dist/mkBin` in sbt to get a build and the runner scripts in `build/quick/bin`
+ - run "Build" - "Make Project" in IntelliJ
+
+Now you can edit and build in IntelliJ and use the scripts (compiler, REPL) to
+directly test your changes. You can also run the `scala`, `scalac` and `partest`
+commands in sbt. Enable "ant mode" (explained above) to prevent sbt's incremental
+compiler from re-compiling (too many) files before each `partest` invocation.
+
+# Coding Guidelines
+
+Our guidelines for contributing are explained in [CONTRIBUTING.md](CONTRIBUTING.md).
+It contains useful information on our coding standards, testing, documentation, how
+we use git and GitHub and how to get your code reviewed.
+
+You may also want to check out the following resources:
+ - The ["Scala Hacker Guide"](http://scala-lang.org/contribute/hacker-guide.html)
+ covers some of the same ground as this README, but in greater detail and in a more
+ tutorial style, using a running example.
+ - [Scala documentation site](http://docs.scala-lang.org)
+
+# Scala CI
+
+Once you submit a PR your commits will are automatically tested by the Scala CI.
+
+If you see a spurious build failure, you can post `/rebuild` as a PR comment.
+The [scabot README](https://github.com/scala/scabot) lists all available commands.
+
+If you'd like to test your patch before having everything polished for review,
+feel free to submit a PR and add the `WIP` label. In case your WIP branch contains
+a large number of commits (that you didn't clean up / squash yet for review),
+consider adding `[ci: last-only]` to the PR title. That way only the last commit
+will be tested, saving some energy and CI-resources. Note that inactive WIP PRs
+will be closed eventually, which does not mean the change is being rejected.
+
+CI performs a full bootstrap. The first task, `validate-publish-core`, publishes
+a build of your commit to the temporary repository
+https://scala-ci.typesafe.com/artifactory/scala-pr-validation-snapshots.
+Note that this build is not yet bootstrapped, its bytecode is built using the
+current `starr`. The version number is `2.12.0-abcd123-SNAPSHOT` where `abcd123`
+is the commit hash.
+
+You can use Scala builds in the validation repository locally by adding a resolver
+and specifying the corresponding `scalaVersion`:
```
$ sbt
-
> set resolvers += "pr" at "https://scala-ci.typesafe.com/artifactory/scala-pr-validation-snapshots/"
-> set scalaVersion := "<milestone>-<sha7>-SNAPSHOT"
+> set scalaVersion := "2.12.0-abcd123-SNAPSHOT"
> console
```
-Here, `<milestone>` is the milestone targeted by the PR (e.g., 2.11.6), and `<sha7>` is the 7-character sha (the format used by GitHub on the web).
-
-## IDE Setup
-### Eclipse
-See [src/eclipse/README.md](src/eclipse/README.md).
-
-### IntelliJ 15
-See [src/intellij/README.md](src/intellij/README.md).
-
-## Building with sbt (EXPERIMENTAL)
-
-The experimental sbt-based build definition has arrived! Run `sbt package`
-to build the compiler. You can run `sbt test` to run unit (JUnit) tests.
-Use `sbt test/it:test` to run integration (partest) tests.
-
-We would like to migrate to sbt build as quickly as possible. If you would
-like to help please use the scala-internals mailing list to discuss your
-ideas and coordinate your effort with others.
-
-## Building with Ant
+Note that the scala modules are currently not built / published against the
+tested version during CI validation.
-NOTE: we are working on migrating the build to sbt.
+## Nightly Builds
-If you are behind a HTTP proxy, include
-[`ANT_ARGS=-autoproxy`](https://ant.apache.org/manual/proxy.html) in
-your environment.
+The Scala CI builds nightly download releases (including all modules) and publishes
+them to the following locations:
+ - [2.12.x](http://www.scala-lang.org/files/archive/nightly/2.12.x/?C=M;O=D)
+ - [2.11.x](http://www.scala-lang.org/files/archive/nightly/2.11.x/?C=M;O=A)
-Run `ant build-opt` to build an optimized version of the compiler.
-Verify your build using `ant test-opt`.
+The CI also publishes nightly API docs:
+ - [2.12.x](http://www.scala-lang.org/files/archive/nightly/2.12.x/api/?C=M;O=D)
+ - [symlink to the latest](http://www.scala-lang.org/files/archive/nightly/2.12.x/api/2.12.x/)
+ - [2.11.x](http://www.scala-lang.org/files/archive/nightly/2.11.x/api/?C=M;O=D)
+ - [symlink to the latest](http://www.scala-lang.org/files/archive/nightly/2.11.x/api/2.11.x/)
-The Scala build system is based on Apache Ant. Most required pre-compiled
-libraries are part of the repository (in 'lib/'). The following however is
-assumed to be installed on the build machine: TODO
+Note that we currently don't publish nightly (or SNAPSHOT) builds in maven or ivy
+format to any repository. You can track progress on this front at
+[scala-jenkins-infra#133](https://github.com/scala/scala-jenkins-infra/issues/133)
+and [scala-dev#68](https://github.com/scala/scala-dev/issues/68).
-### Ant Tips and tricks
+## Scala CI Internals
-Here are some common commands. Most ant targets offer a `-opt` variant that runs under `-optimise` (CI runs the -optimize variant).
-
-Command | Description
------------------------ | -----------
-`./pull-binary-libs.sh` | downloads all binary artifacts associated with this commit.
-`ant -p` | prints out information about the commonly used ant targets.
-`ant` or `ant build` | A quick compilation (to `build/quick`) of your changes using the locker compiler.
-`ant dist` | builds a distribution in 'dists/latest'.
-`ant all.clean` | removes all build files and all distributions.
-
-A typical debug cycle incrementally builds quick, then uses it to compile and run the file
-`sandbox/test.scala` as follows:
-
- - `ant && build/quick/bin/scalac -d sandbox sandbox/test.scala && build/quick/bin/scala -cp sandbox Test`
-
-We typically alias `build/quick/bin/scalac -d sandbox` to `qsc` and `build/quick/bin/scala -cp sandbox` to `qs` in our shell.
-
-`ant test-opt` tests that your code is working and fit to be committed:
-
- - Runs the test suite and bootstrapping test on quick.
- - You can run the suite only (skipping strap) with `ant test.suite`.
-
-`ant docs` generates the HTML documentation for the library from the sources using the scaladoc tool in quick.
-Note: on most machines this requires more heap than is allocated by default. You can adjust the parameters with `ANT_OPTS`. Example command line:
-
-```sh
-ANT_OPTS="-Xms512M -Xmx2048M -Xss1M" ant docs
-```
+The Scala CI runs as a Jenkins instance on [scala-ci.typesafe.com](https://scala-ci.typesafe.com/),
+configured by a chef cookbook at [scala/scala-jenkins-infra](https://github.com/scala/scala-jenkins-infra).
-### Bootstrapping concepts
-NOTE: This is somewhat outdated, but the ideas still hold.
+The build bot that watches PRs, triggers testing builds and applies the "reviewed" label
+after an LGTM comment is in the [scala/scabot](https://github.com/scala/scabot) repo.
-In order to guarantee the bootstrapping of the Scala compiler, the ant build
-compiles Scala in layers. Each layer is a complete compiled Scala compiler and library.
-A superior layer is always compiled by the layer just below it. Here is a short
-description of the four layers that the build uses, from bottom to top:
+## Community Build
- - `starr`: the stable reference Scala release. We use an official version of Scala (specified by `starr.version` in `versions.properties`), downloaded from the Central Repository.
- - `locker`: the local reference which is compiled by starr and is the work compiler in a typical development cycle. Add `locker.skip=true` to `build.properties` to skip this step and speed up development when you're not changing code generation. In any case, after it has been built once, it is “frozen” in this state. Updating it to fit the current source code must be explicitly requested (`ant locker.unlock`).
- - `quick`: the layer which is incrementally built when testing changes in the compiler or library. This is considered an actual new version when locker is up-to-date in relation to the source code.
- - `strap`: a test layer used to check stability of the build.
+The community build is a central element for testing Scala releases. A community
+build can be launched for any Scala revision / commit. It first builds the Scala
+library and compiler and then uses that Scala version to build a large number of
+open-source projects from source.
-For each layer, the Scala library is compiled first and the compiler next.
-That means that any changes in the library can immediately be used in the
-compiler without an intermediate build. On the other hand, if building the
-library requires changes in the compiler, a new locker must be built if
-bootstrapping is still possible, or a new starr if it is not.
+Community builds run on the Scala Jenkins instance, the jobs are named
+`..-integrate-community-build`. The community build definitions specifying which
+projects are built are in the
+[scala/community-builds](https://github.com/scala/community-builds) repo.
diff --git a/build.sbt b/build.sbt
index e9ea2c7153..d592b86aff 100644
--- a/build.sbt
+++ b/build.sbt
@@ -4,7 +4,7 @@
* What you see below is very much work-in-progress. The following features are implemented:
* - Compiling all classses for the compiler and library ("compile" in the respective subprojects)
* - Running JUnit tests ("test") and partest ("test/it:test")
- * - Creating build/quick with all compiled classes and launcher scripts ("˜")
+ * - Creating build/quick with all compiled classes and launcher scripts ("dist/mkQuick")
* - Creating build/pack with all JARs and launcher scripts ("dist/mkPack")
* - Building all scaladoc sets ("doc")
* - Publishing ("publishDists" and standard sbt tasks like "publish" and "publishLocal")
@@ -208,7 +208,9 @@ lazy val commonSettings = clearSourceAndResourceDirectories ++ publishSettings +
// Don't log process output (e.g. of forked `compiler/runMain ...Main`), just pass it
// directly to stdout
- outputStrategy in run := Some(StdoutOutput)
+ outputStrategy in run := Some(StdoutOutput),
+ Quiet.silenceScalaBinaryVersionWarning,
+ Quiet.silenceIvyUpdateInfoLogging
)
/** Extra post-processing for the published POM files. These are needed to create POMs that
@@ -494,6 +496,7 @@ lazy val replJlineEmbedded = Project("repl-jline-embedded", file(".") / "target"
JarJar(inputs, outdir, config)
}),
connectInput in run := true
+
)
.dependsOn(replJline)
@@ -504,7 +507,7 @@ lazy val scaladoc = configureAsSubproject(project)
name := "scala-compiler-doc",
description := "Scala Documentation Generator",
libraryDependencies ++= Seq(scalaXmlDep, scalaParserCombinatorsDep, partestDep),
- includeFilter in unmanagedResources in Compile := "*.html" | "*.css" | "*.gif" | "*.png" | "*.js" | "*.txt"
+ includeFilter in unmanagedResources in Compile := "*.html" | "*.css" | "*.gif" | "*.png" | "*.js" | "*.txt" | "*.svg" | "*.eot" | "*.woff" | "*.ttf"
)
.dependsOn(compiler)
@@ -686,7 +689,8 @@ lazy val root = (project in file("."))
genprod.main(Array(dir.getPath))
GenerateAnyVals.run(dir.getAbsoluteFile)
state
- }
+ },
+ Quiet.silenceIvyUpdateInfoLogging
)
.aggregate(library, reflect, compiler, interactive, repl, replJline, replJlineEmbedded,
scaladoc, scalap, partestExtras, junit, libraryAll, scalaDist).settings(
diff --git a/build.xml b/build.xml
index 8790bf637d..778bcc561b 100644
--- a/build.xml
+++ b/build.xml
@@ -1163,7 +1163,7 @@ TODO:
</pre>
<!-- JSR-223 support introduced in 2.11 -->
<jar-opts>
- <service type="javax.script.ScriptEngineFactory" provider="scala.tools.nsc.interpreter.IMain$Factory"/>
+ <service type="javax.script.ScriptEngineFactory" provider="scala.tools.nsc.interpreter.Scripted$Factory"/>
</jar-opts>
</staged-pack>
</target>
diff --git a/project/Quiet.scala b/project/Quiet.scala
new file mode 100644
index 0000000000..de30ebe6ab
--- /dev/null
+++ b/project/Quiet.scala
@@ -0,0 +1,33 @@
+import sbt._
+import Keys._
+
+object Quiet {
+ // Workaround SBT issue described:
+ //
+ // https://github.com/scala/scala-dev/issues/100
+ def silenceScalaBinaryVersionWarning = ivyConfiguration := {
+ ivyConfiguration.value match {
+ case c: InlineIvyConfiguration =>
+ val delegate = c.log
+ val logger = new Logger {
+ override def trace(t: => Throwable): Unit = delegate.trace(t)
+ override def log(level: sbt.Level.Value, message: => String): Unit = {
+ level match {
+ case sbt.Level.Warn =>
+ val message0 = message
+ val newLevel = if (message.contains("differs from Scala binary version in project"))
+ delegate.log(sbt.Level.Debug, message)
+ else
+ delegate.log(level, message)
+ case _ => delegate.log(level, message)
+ }
+ }
+ override def success(message: => String): Unit = delegate.success(message)
+ }
+ new InlineIvyConfiguration(c.paths, c.resolvers, c.otherResolvers, c.moduleConfigurations, c.localOnly, c.lock, c.checksums, c.resolutionCacheDir, c.updateOptions, logger)
+ case x => x
+ }
+ }
+
+ def silenceIvyUpdateInfoLogging = logLevel in update := Level.Warn
+}
diff --git a/project/plugins.sbt b/project/plugins.sbt
index 23e71c1f26..ac60cd3dd2 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -1,6 +1,6 @@
libraryDependencies += "org.apache.commons" % "commons-lang3" % "3.3.2"
-libraryDependencies += "org.pantsbuild" % "jarjar" % "1.6.0"
+libraryDependencies += "org.pantsbuild" % "jarjar" % "1.6.3"
libraryDependencies += "biz.aQute.bnd" % "biz.aQute.bnd" % "2.4.1"
diff --git a/spec/02-identifiers-names-and-scopes.md b/spec/02-identifiers-names-and-scopes.md
index 0a9c5dfe77..6653be2ce5 100644
--- a/spec/02-identifiers-names-and-scopes.md
+++ b/spec/02-identifiers-names-and-scopes.md
@@ -17,12 +17,12 @@ which are collectively called _bindings_.
Bindings of different kinds have a precedence defined on them:
1. Definitions and declarations that are local, inherited, or made
- available by a package clause in the same compilation unit where the
- definition occurs have highest precedence.
+ available by a package clause and also defined in the same compilation unit
+ as the reference, have highest precedence.
1. Explicit imports have next highest precedence.
1. Wildcard imports have next highest precedence.
-1. Definitions made available by a package clause not in the
- compilation unit where the definition occurs have lowest precedence.
+1. Definitions made available by a package clause, but not also defined in the
+ same compilation unit as the reference, have lowest precedence.
There are two different name spaces, one for [types](03-types.html#types)
and one for [terms](06-expressions.html#expressions). The same name may designate a
@@ -34,22 +34,18 @@ in some inner scope _shadows_ bindings of lower precedence in the
same scope as well as bindings of the same or lower precedence in outer
scopes.
-<!-- TODO: either the example, the spec, or the compiler is wrong
-
-Note that shadowing is only a partial order. In a situation like
+Note that shadowing is only a partial order. In the following example,
+neither binding of `x` shadows the other. Consequently, the
+reference to `x` in the last line of the block is ambiguous.
```scala
val x = 1
-{
- import p.x
+locally {
+ import p.X.x
x
}
```
-neither binding of `x` shadows the other. Consequently, the
-reference to `x` in the last line of the block above would be ambiguous.
--->
-
A reference to an unqualified (type- or term-) identifier $x$ is bound
by the unique binding, which
@@ -69,17 +65,36 @@ the member of the type $T$ of $e$ which has the name $x$ in the same
namespace as the identifier. It is an error if $T$ is not a [value type](03-types.html#value-types).
The type of $e.x$ is the member type of the referenced entity in $T$.
+Binding precedence implies that the way source is bundled in files affects name resolution.
+In particular, imported names have higher precedence than names, defined in other files,
+that might otherwise be visible because they are defined in
+either the current package or an enclosing package.
+
+Note that a package definition is taken as lowest precedence, since packages
+are open and can be defined across arbitrary compilation units.
+
+```scala
+package util {
+ import scala.util
+ class Random
+ object Test extends App {
+ println(new util.Random) // scala.util.Random
+ }
+}
+```
+
###### Example
-Assume the following two definitions of objects named `X` in packages `P` and `Q`.
+Assume the following two definitions of objects named `X` in packages `p` and `q`
+in separate compilation units.
```scala
-package P {
+package p {
object X { val x = 1; val y = 2 }
}
-package Q {
- object X { val x = true; val y = "" }
+package q {
+ object X { val x = true; val y = false }
}
```
@@ -87,25 +102,27 @@ The following program illustrates different kinds of bindings and
precedences between them.
```scala
-package P { // `X' bound by package clause
-import Console._ // `println' bound by wildcard import
-object A {
- println("L4: "+X) // `X' refers to `P.X' here
- object B {
- import Q._ // `X' bound by wildcard import
- println("L7: "+X) // `X' refers to `Q.X' here
- import X._ // `x' and `y' bound by wildcard import
- println("L8: "+x) // `x' refers to `Q.X.x' here
- object C {
- val x = 3 // `x' bound by local definition
- println("L12: "+x) // `x' refers to constant `3' here
- { import Q.X._ // `x' and `y' bound by wildcard import
-// println("L14: "+x) // reference to `x' is ambiguous here
- import X.y // `y' bound by explicit import
- println("L16: "+y) // `y' refers to `Q.X.y' here
- { val x = "abc" // `x' bound by local definition
- import P.X._ // `x' and `y' bound by wildcard import
-// println("L19: "+y) // reference to `y' is ambiguous here
- println("L20: "+x) // `x' refers to string "abc" here
+package p { // `X' bound by package clause
+import Console._ // `println' bound by wildcard import
+object Y {
+ println(s"L4: $X") // `X' refers to `p.X' here
+ locally {
+ import q._ // `X' bound by wildcard import
+ println(s"L7: $X") // `X' refers to `q.X' here
+ import X._ // `x' and `y' bound by wildcard import
+ println(s"L9: $x") // `x' refers to `q.X.x' here
+ locally {
+ val x = 3 // `x' bound by local definition
+ println(s"L12: $x") // `x' refers to constant `3' here
+ locally {
+ import q.X._ // `x' and `y' bound by wildcard import
+// println(s"L15: $x") // reference to `x' is ambiguous here
+ import X.y // `y' bound by explicit import
+ println(s"L17: $y") // `y' refers to `q.X.y' here
+ locally {
+ val x = "abc" // `x' bound by local definition
+ import p.X._ // `x' and `y' bound by wildcard import
+// println(s"L21: $y") // reference to `y' is ambiguous here
+ println(s"L22: $x") // `x' refers to string "abc" here
}}}}}}
```
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index 9c0174d89b..0254141bfb 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -1964,8 +1964,8 @@ self =>
case _ => EmptyTree
}
def loop(top: Tree): Tree = reducePatternStack(base, top) match {
- case next if isIdentExcept(raw.BAR) => pushOpInfo(next) ; loop(simplePattern(badPattern3))
- case next => next
+ case next if isIdent && !isRawBar => pushOpInfo(next) ; loop(simplePattern(badPattern3))
+ case next => next
}
checkWildStar orElse stripParens(loop(top))
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
index a32c21795d..a5744983b2 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
@@ -76,7 +76,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
val origOwner = sym.originalOwner
// phase travel necessary: after flatten, the name includes the name of outer classes.
// if some outer name contains $anon, a non-anon class is considered anon.
- if (delambdafyInline() && sym.rawowner.isAnonymousFunction) {
+ if (delambdafyInline() && exitingPickler(sym.rawowner.isAnonymousFunction)) {
// SI-9105: special handling for anonymous functions under delambdafy:inline.
//
// class C { def t = () => { def f { class Z } } }
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
index f190c1f2de..bddc41e5c6 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
@@ -164,8 +164,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
} else {
- val skipStaticForwarders = (claszSymbol.isInterface || settings.noForwarders)
- if (!skipStaticForwarders) {
+ if (!settings.noForwarders) {
val lmoc = claszSymbol.companionModule
// add static forwarders if there are no name conflicts; see bugs #363 and #1735
if (lmoc != NoSymbol) {
diff --git a/src/compiler/scala/tools/nsc/classpath/AggregateClassPath.scala b/src/compiler/scala/tools/nsc/classpath/AggregateClassPath.scala
index 6b435542a3..a1af3413ea 100644
--- a/src/compiler/scala/tools/nsc/classpath/AggregateClassPath.scala
+++ b/src/compiler/scala/tools/nsc/classpath/AggregateClassPath.scala
@@ -6,6 +6,7 @@ package scala.tools.nsc.classpath
import java.net.URL
import scala.annotation.tailrec
import scala.collection.mutable.ArrayBuffer
+import scala.reflect.internal.FatalError
import scala.reflect.io.AbstractFile
import scala.tools.nsc.util.ClassPath
import scala.tools.nsc.util.ClassRepresentation
@@ -72,7 +73,16 @@ case class AggregateClassPath(aggregates: Seq[ClassPath]) extends ClassPath {
getDistinctEntries(_.sources(inPackage))
override private[nsc] def list(inPackage: String): ClassPathEntries = {
- val (packages, classesAndSources) = aggregates.map(_.list(inPackage)).unzip
+ val (packages, classesAndSources) = aggregates.map { cp =>
+ try {
+ cp.list(inPackage)
+ } catch {
+ case ex: java.io.IOException =>
+ val e = new FatalError(ex.getMessage)
+ e.initCause(ex)
+ throw e
+ }
+ }.unzip
val distinctPackages = packages.flatten.distinct
val distinctClassesAndSources = mergeClassesAndSources(classesAndSources: _*)
ClassPathEntries(distinctPackages, distinctClassesAndSources)
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 0301e06c87..5e903946c1 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -344,7 +344,7 @@ abstract class Erasure extends AddInterfaces
buf.toString
case RefinedType(parents, decls) =>
- boxedSig(intersectionDominator(parents))
+ jsig(intersectionDominator(parents), primitiveOK = primitiveOK)
case ClassInfoType(parents, _, _) =>
superSig(parents)
case AnnotatedType(_, atp) =>
@@ -606,10 +606,8 @@ abstract class Erasure extends AddInterfaces
// !!! Make pending/run/t5866b.scala work. The fix might be here and/or in unbox1.
if (isPrimitiveValueType(targ.tpe) || isErasedValueType(targ.tpe)) {
val noNullCheckNeeded = targ.tpe match {
- case ErasedValueType(_, underlying) =>
- isPrimitiveValueClass(underlying.typeSymbol)
- case _ =>
- true
+ case ErasedValueType(_, underlying) => isPrimitiveValueType(underlying)
+ case _ => true
}
if (noNullCheckNeeded) unbox(qual1, targ.tpe)
else {
@@ -1143,6 +1141,10 @@ abstract class Erasure extends AddInterfaces
else {
val tree1 = preErase(tree)
tree1 match {
+ case TypeApply(fun, targs @ List(targ)) if fun.symbol == Any_asInstanceOf && targ.tpe == UnitTpe =>
+ // SI-9066 prevent transforming `o.asInstanceOf[Unit]` to `o.asInstanceOf[BoxedUnit]`.
+ // adaptMember will then replace the call by a reference to BoxedUnit.UNIT.
+ treeCopy.TypeApply(tree1, transform(fun), targs).clearType()
case EmptyTree | TypeTree() =>
tree1 setType specialScalaErasure(tree1.tpe)
case ArrayValue(elemtpt, trees) =>
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index 4b1f1efee4..e894c58b1a 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -1911,8 +1911,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
/** Forward to the generic class constructor. If the current class initializes
* specialized fields corresponding to parameters, it passes null to the superclass
- * constructor. This saves the boxing cost for initializing generic fields that are
- * never used.
+ * constructor.
*
* For example:
* {{{
@@ -1926,7 +1925,17 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
* super.this(null.asInstanceOf[Int], null.asInstanceOf[Int])
* }
* }
- * }}
+ * }}}
+ *
+ * Note that erasure first transforms `null.asInstanceOf[Int]` to `unbox(null)`, which is 0.
+ * Then it adapts the argument `unbox(null)` of type Int to the erased parameter type of Tuple2,
+ * which is Object, so it inserts a `box` call and we get `box(unbox(null))`, which is
+ * `new Integer(0)` (not `null`).
+ *
+ * However it does not make sense to create an Integer instance to be stored in the generic field
+ * of the superclass: that field is never used. Therefore we mark the `null` tree with the
+ * [[SpecializedSuperConstructorCallArgument]] attachment and special-case erasure to replace
+ * `box(unbox(null))` by `null` in this case.
*/
private def forwardCtorCall(pos: scala.reflect.internal.util.Position, receiver: Tree, paramss: List[List[ValDef]], clazz: Symbol): Tree = {
log(s"forwardCtorCall($pos, $receiver, $paramss, $clazz)")
@@ -1945,7 +1954,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
val argss = mmap(paramss)(x =>
if (initializesSpecializedField(x.symbol))
- gen.mkAsInstanceOf(Literal(Constant(null)), x.symbol.tpe)
+ gen.mkAsInstanceOf(Literal(Constant(null)).updateAttachment(SpecializedSuperConstructorCallArgument), x.symbol.tpe)
else
Ident(x.symbol)
)
@@ -1989,5 +1998,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
}
resultTree
- } }
+ }
+ }
+ object SpecializedSuperConstructorCallArgument
}
diff --git a/src/compiler/scala/tools/nsc/transform/TypeAdaptingTransformer.scala b/src/compiler/scala/tools/nsc/transform/TypeAdaptingTransformer.scala
index afafdedce7..52d7c0b897 100644
--- a/src/compiler/scala/tools/nsc/transform/TypeAdaptingTransformer.scala
+++ b/src/compiler/scala/tools/nsc/transform/TypeAdaptingTransformer.scala
@@ -14,11 +14,18 @@ trait TypeAdaptingTransformer { self: TreeDSL =>
def typedPos(pos: Position)(tree: Tree): Tree
+ /**
+ * SI-4148: can't always replace box(unbox(x)) by x because
+ * - unboxing x may lead to throwing an exception, e.g. in "aah".asInstanceOf[Int]
+ * - box(unbox(null)) is not `null` but the box of zero
+ */
private def isSafelyRemovableUnbox(fn: Tree, arg: Tree): Boolean = {
- currentRun.runDefinitions.isUnbox(fn.symbol) && {
- val cls = arg.tpe.typeSymbol
- (cls == NullClass) || isBoxedValueClass(cls)
- }
+ currentRun.runDefinitions.isUnbox(fn.symbol) && {
+ // replace box(unbox(null)) by null when passed to the super constructor in a specialized
+ // class, see comment in SpecializeTypes.forwardCtorCall.
+ arg.hasAttachment[specializeTypes.SpecializedSuperConstructorCallArgument.type] ||
+ isBoxedValueClass(arg.tpe.typeSymbol)
+ }
}
private def isPrimitiveValueType(tpe: Type) = isPrimitiveValueClass(tpe.typeSymbol)
@@ -44,14 +51,7 @@ trait TypeAdaptingTransformer { self: TreeDSL =>
case x =>
assert(x != ArrayClass)
tree match {
- /* Can't always remove a Box(Unbox(x)) combination because the process of boxing x
- * may lead to throwing an exception.
- *
- * This is important for specialization: calls to the super constructor should not box/unbox specialized
- * fields (see TupleX). (ID)
- */
case Apply(boxFun, List(arg)) if isSafelyRemovableUnbox(tree, arg) =>
- log(s"boxing an unbox: ${tree.symbol} -> ${arg.tpe}")
arg
case _ =>
(REF(currentRun.runDefinitions.boxMethod(x)) APPLY tree) setPos (tree.pos) setType ObjectTpe
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index ccdff5c9a1..90ccaefe43 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -198,7 +198,7 @@ trait ContextErrors {
val foundType: Type = req.dealiasWiden match {
case RefinedType(parents, decls) if !decls.isEmpty && found.typeSymbol.isAnonOrRefinementClass =>
val retyped = typed (tree.duplicate.clearType())
- val foundDecls = retyped.tpe.decls filter (sym => !sym.isConstructor && !sym.isSynthetic)
+ val foundDecls = retyped.tpe.decls filter (sym => !sym.isConstructor && !sym.isSynthetic && !sym.isErroneous)
if (foundDecls.isEmpty || (found.typeSymbol eq NoSymbol)) found
else {
// The members arrive marked private, presumably because there was no
@@ -212,7 +212,8 @@ trait ContextErrors {
case _ =>
found
}
- assert(!foundType.isErroneous && !req.isErroneous, (foundType, req))
+ assert(!foundType.isErroneous, s"AdaptTypeError - foundType is Erroneous: $foundType")
+ assert(!req.isErroneous, s"AdaptTypeError - req is Erroneous: $req")
issueNormalTypeError(callee, withAddendum(callee.pos)(typeErrorMsg(foundType, req)))
infer.explainTypes(foundType, req)
@@ -469,6 +470,11 @@ trait ContextErrors {
setError(tree)
}
+ def ConstructorRecursesError(tree: Tree) = {
+ issueNormalTypeError(tree, "constructor invokes itself")
+ setError(tree)
+ }
+
def OnlyDeclarationsError(tree: Tree) = {
issueNormalTypeError(tree, "only declarations allowed here")
setError(tree)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 8f5c4b9f6d..329ce8c23b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2992,43 +2992,36 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
def includesTargetPos(tree: Tree) =
tree.pos.isRange && context.unit.exists && (tree.pos includes context.unit.targetPos)
val localTarget = stats exists includesTargetPos
- def typedStat(stat: Tree): Tree = {
- if (context.owner.isRefinementClass && !treeInfo.isDeclarationOrTypeDef(stat))
- OnlyDeclarationsError(stat)
- else
- stat match {
- case imp @ Import(_, _) =>
- imp.symbol.initialize
- if (!imp.symbol.isError) {
- context = context.make(imp)
- typedImport(imp)
- } else EmptyTree
- case _ =>
- if (localTarget && !includesTargetPos(stat)) {
- // skip typechecking of statements in a sequence where some other statement includes
- // the targetposition
- stat
- } else {
- val localTyper = if (inBlock || (stat.isDef && !stat.isInstanceOf[LabelDef])) {
- this
- } else newTyper(context.make(stat, exprOwner))
- // XXX this creates a spurious dead code warning if an exception is thrown
- // in a constructor, even if it is the only thing in the constructor.
- val result = checkDead(localTyper.typedByValueExpr(stat))
-
- if (treeInfo.isSelfOrSuperConstrCall(result)) {
- context.inConstructorSuffix = true
- if (treeInfo.isSelfConstrCall(result) && result.symbol.pos.pointOrElse(0) >= exprOwner.enclMethod.pos.pointOrElse(0))
- ConstructorsOrderError(stat)
- }
-
- if (!isPastTyper && treeInfo.isPureExprForWarningPurposes(result)) context.warning(stat.pos,
- "a pure expression does nothing in statement position; " +
- "you may be omitting necessary parentheses"
- )
- result
- }
+ def typedStat(stat: Tree): Tree = stat match {
+ case s if context.owner.isRefinementClass && !treeInfo.isDeclarationOrTypeDef(s) => OnlyDeclarationsError(s)
+ case imp @ Import(_, _) =>
+ imp.symbol.initialize
+ if (!imp.symbol.isError) {
+ context = context.make(imp)
+ typedImport(imp)
+ } else EmptyTree
+ // skip typechecking of statements in a sequence where some other statement includes the targetposition
+ case s if localTarget && !includesTargetPos(s) => s
+ case _ =>
+ val localTyper = if (inBlock || (stat.isDef && !stat.isInstanceOf[LabelDef])) this
+ else newTyper(context.make(stat, exprOwner))
+ // XXX this creates a spurious dead code warning if an exception is thrown
+ // in a constructor, even if it is the only thing in the constructor.
+ val result = checkDead(localTyper.typedByValueExpr(stat))
+
+ if (treeInfo.isSelfOrSuperConstrCall(result)) {
+ context.inConstructorSuffix = true
+ if (treeInfo.isSelfConstrCall(result)) {
+ if (result.symbol == exprOwner.enclMethod)
+ ConstructorRecursesError(stat)
+ else if (result.symbol.pos.pointOrElse(0) >= exprOwner.enclMethod.pos.pointOrElse(0))
+ ConstructorsOrderError(stat)
+ }
}
+ if (!isPastTyper && treeInfo.isPureExprForWarningPurposes(result)) context.warning(stat.pos,
+ "a pure expression does nothing in statement position; you may be omitting necessary parentheses"
+ )
+ result
}
/* 'accessor' and 'accessed' are so similar it becomes very difficult to
diff --git a/src/intellij/README.md b/src/intellij/README.md
index dcad699d43..41fef04183 100644
--- a/src/intellij/README.md
+++ b/src/intellij/README.md
@@ -1,25 +1,25 @@
-# Building Scala in IntelliJ IDEA
-
-## Requirements
+# Developing Scala in IntelliJ IDEA
Use the latest IntelliJ release and install the Scala plugin from within the IDE.
-## Initial setup
+## Initial Setup
To create the IntelliJ project files:
- Run `sbt intellij`
- Open `src/intellij/scala.ipr` in IntelliJ
- - In `File` → `Project Structure` → `Project` → `Project SDK`, create an SDK entry named "1.8" containing the Java 1.8 SDK
+ - In `File` → `Project Structure` → `Project` → `Project SDK`, create an SDK entry
+ named "1.8" containing the Java 1.8 SDK (1.6 if you're on the Scala the 2.11.x branch)
-The project files are created by as copies of the `.SAMPLE` files, which are under version control.
-The actual IntelliJ project files are in `.gitignore` so that local changes are ignored.
+The project files are created as copies of the `.SAMPLE` files, which are under version
+control. The actual IntelliJ project files are in `.gitignore` so that local changes
+are ignored.
## Dependencies
For every module in the IntelliJ project there is a corresponding `-deps` library, for exmaple `compiler-deps` provides `ant.jar` for the compiler codebase.
The `.jar` files in these `-deps` libraries can be easily kept up-to-date by running `sbt intellij` again.
-This is necessary whenever the dependencies in the sbt build change, for example when the STARR version is updated.
+This is necessary whenever the dependencies in the sbt build change, for example when the `starr` version is updated.
Note that this command only patches the dependency lists, all other settings in the IntelliJ project definition are unchanged.
To overwrite the project definition files by copying the `.SAMPLE` files again run `sbt intellijFromSample`.
@@ -33,17 +33,49 @@ When switching between 2.11.x and 2.12.x, make sure to run `sbt intellij`.
Note that the `Project SDK` is not updated in this process.
If you want to use the Java 1.6 SDK while working on 2.11.x you need to change it manually (`File` → `Project Structure` → `Project` → `Project SDK`).
-## Usage
+If you switch between 2.11.x and 2.12.x often, it makes sense to have a separate clone
+of the repository for each branch.
+
+## Incremental Compilation
+
+Run `Build` → `Make Project` to build all modules of the Scala repository (library,
+compiler, etc). Note that compilation IntelliJ is performed in a single pass (no
+bootstrap), like the sbt build.
+
+Note that the output directory when compiling in IntelliJ is the same as for the
+sbt and (deprecated) ant builds. This allows building incrementally in IntelliJ
+and directly use the changes using the command-line scripts in `build/quick/bin/`.
+
+## Running JUnit Tests
+
+JUnit tests can be executed by right-clicking on a test class or test method and
+selecting "Run" or "Debug". The debugger will allow you to stop at breakpoints
+within the Scala library.
+
+It is possible to invoke the Scala compiler from a JUnit test (passing the source
+code as a string) and inspect the generated bytecode, see for example
+`scala.issues.BytecodeTest`. Debugging such a test is an easy way to stop at
+breakpoints within the Scala compiler.
+
+## Running the Compiler and REPL
+
+You can create run/debug configurations to run the compiler and REPL directly within
+IntelliJ, which might accelerate development and debugging of the the compiler.
-Compiling, running, JUnit tests and debugging should all work.
-You can work on the compiler, the standard library, and other components as well.
+To debug the Scala codebase you can also use "Remote" debug configuration and pass
+the corresponding arguments to the jvm running the compiler / program.
-Note that compilation within IntelliJ is performed in a single pass.
-The code is compiled using the "STARR" (stable reference) compiler, as specified by `starr.version` in `versions.properties`.
-This is consistent with the sbt build.
+To run the compiler create an "Application" configuration with
+ - Main class: `scala.tools.nsc.Main`
+ - Program arguments: `-usejavacp -cp sandbox -d sandbox sandbox/Test.scala`
+ - Working directory: the path of your checkout
+ - Use classpath of module: `compiler`
-Note that the output directory when compiling in IntelliJ is the same as for the sbt build.
-This allows building incrementally in IntelliJ and directly use the changes using the command-line scripts in `build/quick/bin/`.
+To run the REPL create an "Application" configuration with
+ - Main class: `scala.tools.nsc.MainGenericRunner`
+ - Program arguments: `-usejavacp`
+ - Working directory: the path of your checkout
+ - Use classpath of module: `repl`
## Updating the `.SAMPLE` files
diff --git a/src/library/scala/Console.scala b/src/library/scala/Console.scala
index 37127a93d5..0b079aae15 100644
--- a/src/library/scala/Console.scala
+++ b/src/library/scala/Console.scala
@@ -1,6 +1,6 @@
/* __ *\
** ________ ___ / / ___ Scala API **
-** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
+** / __/ __// _ | / / / _ | (c) 2003-2016, LAMP/EPFL **
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
** /____/\___/_/ |_/____/_/ | | **
** |/ **
@@ -12,12 +12,115 @@ import java.io.{ BufferedReader, InputStream, InputStreamReader, OutputStream, P
import scala.io.{ AnsiColor, StdIn }
import scala.util.DynamicVariable
-/** Implements functionality for
- * printing Scala values on the terminal as well as reading specific values.
+/** Implements functionality for printing Scala values on the terminal. For reading values
+ * use [[scala.io.StdIn$ StdIn]].
* Also defines constants for marking up text on ANSI terminals.
*
+ * == Console Output ==
+ *
+ * Use the print methods to output text.
+ * {{{
+ * scala> Console.printf(
+ * "Today the outside temperature is a balmy %.1f°C. %<.1f°C beats the previous record of %.1f°C.\n",
+ * -137.0,
+ * -135.05)
+ * Today the outside temperature is a balmy -137.0°C. -137.0°C beats the previous record of -135.1°C.
+ * }}}
+ *
+ * == ANSI escape codes ==
+ * Use the ANSI escape codes for colorizing console output either to STDOUT or STDERR.
+ * {{{
+ * import Console.{GREEN, RED, RESET, YELLOW_B, UNDERLINED}
+ *
+ * object PrimeTest {
+ *
+ * def isPrime(): Unit = {
+ *
+ * val candidate = io.StdIn.readInt().ensuring(_ > 1)
+ *
+ * val prime = (2 to candidate - 1).forall(candidate % _ != 0)
+ *
+ * if (prime)
+ * Console.println(s"${RESET}${GREEN}yes${RESET}")
+ * else
+ * Console.err.println(s"${RESET}${YELLOW_B}${RED}${UNDERLINED}NO!${RESET}")
+ * }
+ *
+ * def main(args: Array[String]): Unit = isPrime()
+ *
+ * }
+ * }}}
+ *
+ * <table style="border: 10px solid #000;width:100%">
+ * <tr><td style="background-color:#000;color:#fff">$ scala PrimeTest</td></tr>
+ * <tr><td style="background-color:#000;color:#fff">1234567891</td></tr>
+ * <tr><td style="background-color:#000;color:#0f0">yes</td></tr>
+ * <tr><td style="background-color:#000;color:#fff">$ scala PrimeTest</td></tr>
+ * <tr><td style="background-color:#000;color:#fff">56474</td></tr>
+ * <tr><td style="background-color:#000;color:#fff"><span style="background-color:#ff0;color:#f00;text-decoration:underline">NO!</span></td></tr>
+ * </table>
+ *
+ * == IO redefinition ==
+ *
+ * Use IO redefinition to temporarily swap in a different set of input and/or output streams. In this example the stream based
+ * method above is wrapped into a function.
+ *
+ * {{{
+ * import java.io.{ByteArrayOutputStream, StringReader}
+ *
+ * object FunctionalPrimeTest {
+ *
+ * def isPrime(candidate: Int): Boolean = {
+ *
+ * val input = new StringReader(s"$candidate\n")
+ * val outCapture = new ByteArrayOutputStream
+ * val errCapture = new ByteArrayOutputStream
+ *
+ * Console.withIn(input) {
+ * Console.withOut(outCapture) {
+ * Console.withErr(errCapture) {
+ * PrimeTest.isPrime()
+ * }
+ * }
+ * }
+ *
+ * if (outCapture.toByteArray.nonEmpty) // "yes"
+ * true
+ * else if (errCapture.toByteArray.nonEmpty) // "NO!"
+ * false
+ * else throw new IllegalArgumentException(candidate.toString)
+ * }
+ *
+ * def main(args: Array[String]): Unit = {
+ * val primes = (2 to 50) filter (isPrime)
+ * println(s"First primes: $primes")
+ * }
+ *
+ * }
+ * }}}
+ *
+ *
+ * <table style="border: 10px solid #000;width:100%">
+ * <tr><td style="background-color:#000;color:#fff">$ scala FunctionalPrimeTest</td></tr>
+ * <tr><td style="background-color:#000;color:#fff">First primes: Vector(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47)</td></tr>
+ * </table>
+ *
* @author Matthias Zenger
* @version 1.0, 03/09/2003
+ *
+ * @groupname console-output Console Output
+ * @groupprio console-output 30
+ * @groupdesc console-output These methods provide output via the console.
+ *
+ * @groupname io-default IO Defaults
+ * @groupprio io-default 50
+ * @groupdesc io-default These values provide direct access to the standard IO channels
+ *
+ * @groupname io-redefinition IO Redefinition
+ * @groupprio io-redefinition 60
+ * @groupdesc io-redefinition These methods allow substituting alternative streams for the duration of
+ * a body of code. Threadsafe by virtue of [[scala.util.DynamicVariable]].
+ *
*/
object Console extends DeprecatedConsole with AnsiColor {
private val outVar = new DynamicVariable[PrintStream](java.lang.System.out)
@@ -29,11 +132,17 @@ object Console extends DeprecatedConsole with AnsiColor {
protected def setErrDirect(err: PrintStream): Unit = errVar.value = err
protected def setInDirect(in: BufferedReader): Unit = inVar.value = in
- /** The default output, can be overridden by `setOut` */
+ /** The default output, can be overridden by `withOut`
+ * @group io-default
+ */
def out = outVar.value
- /** The default error, can be overridden by `setErr` */
+ /** The default error, can be overridden by `withErr`
+ * @group io-default
+ */
def err = errVar.value
- /** The default input, can be overridden by `setIn` */
+ /** The default input, can be overridden by `withIn`
+ * @group io-default
+ */
def in = inVar.value
/** Sets the default output stream for the duration
@@ -48,6 +157,7 @@ object Console extends DeprecatedConsole with AnsiColor {
* the new output stream active
* @return the results of `thunk`
* @see `withOut[T](out:OutputStream)(thunk: => T)`
+ * @group io-redefinition
*/
def withOut[T](out: PrintStream)(thunk: =>T): T =
outVar.withValue(out)(thunk)
@@ -60,6 +170,7 @@ object Console extends DeprecatedConsole with AnsiColor {
* the new output stream active
* @return the results of `thunk`
* @see `withOut[T](out:PrintStream)(thunk: => T)`
+ * @group io-redefinition
*/
def withOut[T](out: OutputStream)(thunk: =>T): T =
withOut(new PrintStream(out))(thunk)
@@ -67,7 +178,7 @@ object Console extends DeprecatedConsole with AnsiColor {
/** Set the default error stream for the duration
* of execution of one thunk.
* @example {{{
- * withErr(Console.out) { println("This goes to default _out_") }
+ * withErr(Console.out) { err.println("This goes to default _out_") }
* }}}
*
* @param err the new error stream.
@@ -75,6 +186,7 @@ object Console extends DeprecatedConsole with AnsiColor {
* the new error stream active
* @return the results of `thunk`
* @see `withErr[T](err:OutputStream)(thunk: =>T)`
+ * @group io-redefinition
*/
def withErr[T](err: PrintStream)(thunk: =>T): T =
errVar.withValue(err)(thunk)
@@ -87,6 +199,7 @@ object Console extends DeprecatedConsole with AnsiColor {
* the new error stream active
* @return the results of `thunk`
* @see `withErr[T](err:PrintStream)(thunk: =>T)`
+ * @group io-redefinition
*/
def withErr[T](err: OutputStream)(thunk: =>T): T =
withErr(new PrintStream(err))(thunk)
@@ -105,8 +218,9 @@ object Console extends DeprecatedConsole with AnsiColor {
* @param thunk the code to execute with
* the new input stream active
*
- * @return the results of `thunk`
- * @see `withIn[T](in:InputStream)(thunk: =>T)`
+ * @return the results of `thunk`
+ * @see `withIn[T](in:InputStream)(thunk: =>T)`
+ * @group io-redefinition
*/
def withIn[T](reader: Reader)(thunk: =>T): T =
inVar.withValue(new BufferedReader(reader))(thunk)
@@ -117,8 +231,9 @@ object Console extends DeprecatedConsole with AnsiColor {
* @param in the new input stream.
* @param thunk the code to execute with
* the new input stream active
- * @return the results of `thunk`
- * @see `withIn[T](reader:Reader)(thunk: =>T)`
+ * @return the results of `thunk`
+ * @see `withIn[T](reader:Reader)(thunk: =>T)`
+ * @group io-redefinition
*/
def withIn[T](in: InputStream)(thunk: =>T): T =
withIn(new InputStreamReader(in))(thunk)
@@ -126,6 +241,7 @@ object Console extends DeprecatedConsole with AnsiColor {
/** Prints an object to `out` using its `toString` method.
*
* @param obj the object to print; may be null.
+ * @group console-output
*/
def print(obj: Any) {
out.print(if (null == obj) "null" else obj.toString())
@@ -134,29 +250,31 @@ object Console extends DeprecatedConsole with AnsiColor {
/** Flushes the output stream. This function is required when partial
* output (i.e. output not terminated by a newline character) has
* to be made visible on the terminal.
+ * @group console-output
*/
def flush() { out.flush() }
/** Prints a newline character on the default output.
+ * @group console-output
*/
def println() { out.println() }
/** Prints out an object to the default output, followed by a newline character.
*
* @param x the object to print.
+ * @group console-output
*/
def println(x: Any) { out.println(x) }
/** Prints its arguments as a formatted string to the default output,
* based on a string pattern (in a fashion similar to printf in C).
*
- * The interpretation of the formatting patterns is described in
- * <a href="" target="contentFrame" class="java/util/Formatter">
- * `java.util.Formatter`</a>.
+ * The interpretation of the formatting patterns is described in [[java.util.Formatter]].
*
* @param text the pattern for formatting the arguments.
* @param args the arguments used to instantiating the pattern.
* @throws java.lang.IllegalArgumentException if there was a problem with the format string or arguments
+ * @group console-output
*/
def printf(text: String, args: Any*) { out.print(text format (args : _*)) }
}
diff --git a/src/library/scala/collection/immutable/ListMap.scala b/src/library/scala/collection/immutable/ListMap.scala
index e1bcc0711c..589f8bbba9 100644
--- a/src/library/scala/collection/immutable/ListMap.scala
+++ b/src/library/scala/collection/immutable/ListMap.scala
@@ -6,8 +6,6 @@
** |/ **
\* */
-
-
package scala
package collection
package immutable
@@ -15,214 +13,154 @@ package immutable
import generic._
import scala.annotation.tailrec
-/** $factoryInfo
- * @since 1
- * @see [[http://docs.scala-lang.org/overviews/collections/concrete-immutable-collection-classes.html#list_maps "Scala's Collection Library overview"]]
- * section on `List Maps` for more information.
- *
- * Note that `ListMap` is built in reverse order to canonical traversal order (traversal order is oldest first).
- * Thus, `head` and `tail` are O(n). To rapidly partition a `ListMap` into elements, use `last` and `init` instead. These are O(1).
- *
- * @define Coll immutable.ListMap
- * @define coll immutable list map
- */
+/**
+ * $factoryInfo
+ *
+ * Note that each element insertion takes O(n) time, which means that creating a list map with
+ * n elements will take O(n^2^) time. This makes the builder suitable only for a small number of
+ * elements.
+ *
+ * @see [[http://docs.scala-lang.org/overviews/collections/concrete-immutable-collection-classes.html#list_maps "Scala's Collection Library overview"]]
+ * section on `List Maps` for more information.
+ * @since 1
+ * @define Coll ListMap
+ * @define coll list map
+ */
object ListMap extends ImmutableMapFactory[ListMap] {
- /** $mapCanBuildFromInfo */
+
+ /**
+ * $mapCanBuildFromInfo
+ */
implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), ListMap[A, B]] =
new MapCanBuildFrom[A, B]
+
def empty[A, B]: ListMap[A, B] = EmptyListMap.asInstanceOf[ListMap[A, B]]
@SerialVersionUID(-8256686706655863282L)
- private object EmptyListMap extends ListMap[Any, Nothing] {
- override def apply(key: Any) = throw new NoSuchElementException("key not found: " + key)
- override def contains(key: Any) = false
- override def last: (Any, Nothing) = throw new NoSuchElementException("Empty ListMap")
- override def init: ListMap[Any, Nothing] = throw new NoSuchElementException("Empty ListMap")
- }
+ private object EmptyListMap extends ListMap[Any, Nothing]
}
-/** This class implements immutable maps using a list-based data structure, which preserves insertion order.
- * Instances of `ListMap` represent empty maps; they can be either created by
- * calling the constructor directly, or by applying the function `ListMap.empty`.
- *
- * @tparam A the type of the keys in this list map.
- * @tparam B the type of the values associated with the keys.
- *
- * @author Matthias Zenger
- * @author Martin Odersky
- * @version 2.0, 01/01/2007
- * @since 1
- * @define Coll immutable.ListMap
- * @define coll immutable list map
- * @define mayNotTerminateInf
- * @define willNotTerminateInf
- */
+/**
+ * This class implements immutable maps using a list-based data structure. List map iterators and
+ * traversal methods visit key-value pairs in the order whey were first inserted.
+ *
+ * Entries are stored internally in reversed insertion order, which means the newest key is at the
+ * head of the list. As such, methods such as `head` and `tail` are O(n), while `last` and `init`
+ * are O(1). Other operations, such as inserting or removing entries, are also O(n), which makes
+ * this collection suitable only for a small number of elements.
+ *
+ * Instances of `ListMap` represent empty maps; they can be either created by calling the
+ * constructor directly, or by applying the function `ListMap.empty`.
+ *
+ * @tparam A the type of the keys contained in this list map
+ * @tparam B the type of the values associated with the keys
+ *
+ * @author Matthias Zenger
+ * @author Martin Odersky
+ * @version 2.0, 01/01/2007
+ * @since 1
+ * @define Coll ListMap
+ * @define coll list map
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
@SerialVersionUID(301002838095710379L)
-sealed class ListMap[A, +B]
-extends AbstractMap[A, B]
- with Map[A, B]
- with MapLike[A, B, ListMap[A, B]]
- with Serializable {
+sealed class ListMap[A, +B] extends AbstractMap[A, B]
+ with Map[A, B]
+ with MapLike[A, B, ListMap[A, B]]
+ with Serializable {
override def empty = ListMap.empty
- /** Returns the number of mappings in this map.
- *
- * @return number of mappings in this map.
- */
override def size: Int = 0
+ override def isEmpty: Boolean = true
- /** Checks if this map maps `key` to a value and return the
- * value if it exists.
- *
- * @param key the key of the mapping of interest
- * @return the value of the mapping, if it exists
- */
def get(key: A): Option[B] = None
- /** This method allows one to create a new map with an additional mapping
- * from `key` to `value`. If the map contains already a mapping for `key`,
- * it will be overridden by this function.
- *
- * @param key the key element of the updated entry.
- * @param value the value element of the updated entry.
- */
- override def updated [B1 >: B] (key: A, value: B1): ListMap[A, B1] =
- new Node[B1](key, value)
-
- /** Add a key/value pair to this map.
- * @param kv the key/value pair
- * @return A new map with the new binding added to this map
- */
- def + [B1 >: B] (kv: (A, B1)): ListMap[A, B1] = updated(kv._1, kv._2)
-
- /** Adds two or more elements to this collection and returns
- * either the collection itself (if it is mutable), or a new collection
- * with the added elements.
- *
- * @param elem1 the first element to add.
- * @param elem2 the second element to add.
- * @param elems the remaining elements to add.
- */
- override def + [B1 >: B] (elem1: (A, B1), elem2: (A, B1), elems: (A, B1) *): ListMap[A, B1] =
- this + elem1 + elem2 ++ elems
-
- /** Adds a number of elements provided by a traversable object
- * and returns a new collection with the added elements.
- *
- * @param xs the traversable object.
- */
+ override def updated[B1 >: B](key: A, value: B1): ListMap[A, B1] = new Node[B1](key, value)
+
+ def +[B1 >: B](kv: (A, B1)): ListMap[A, B1] = new Node[B1](kv._1, kv._2)
+ def -(key: A): ListMap[A, B] = this
+
override def ++[B1 >: B](xs: GenTraversableOnce[(A, B1)]): ListMap[A, B1] =
- ((repr: ListMap[A, B1]) /: xs.seq) (_ + _)
-
- /** This creates a new mapping without the given `key`.
- * If the map does not contain a mapping for the given key, the
- * method returns the same map.
- *
- * @param key a map without a mapping for the given key.
- */
- def - (key: A): ListMap[A, B] = this
-
- /** Returns an iterator over key-value pairs.
- */
- def iterator: Iterator[(A,B)] =
- new AbstractIterator[(A,B)] {
- var self: ListMap[A,B] = ListMap.this
- def hasNext = !self.isEmpty
- def next(): (A,B) =
- if (!hasNext) throw new NoSuchElementException("next on empty iterator")
- else { val res = (self.key, self.value); self = self.next; res }
- }.toList.reverseIterator
-
- protected def key: A = throw new NoSuchElementException("empty map")
- protected def value: B = throw new NoSuchElementException("empty map")
- protected def next: ListMap[A, B] = throw new NoSuchElementException("empty map")
-
- /** This class represents an entry in the `ListMap`.
- */
+ if (xs.isEmpty) this
+ else ((repr: ListMap[A, B1]) /: xs) (_ + _)
+
+ def iterator: Iterator[(A, B)] = {
+ def reverseList = {
+ var curr: ListMap[A, B] = this
+ var res: List[(A, B)] = Nil
+ while (!curr.isEmpty) {
+ res = (curr.key, curr.value) :: res
+ curr = curr.next
+ }
+ res
+ }
+ reverseList.iterator
+ }
+
+ protected def key: A = throw new NoSuchElementException("key of empty map")
+ protected def value: B = throw new NoSuchElementException("value of empty map")
+ protected def next: ListMap[A, B] = throw new NoSuchElementException("next of empty map")
+
+ override def stringPrefix = "ListMap"
+
+ /**
+ * Represents an entry in the `ListMap`.
+ */
@SerialVersionUID(-6453056603889598734L)
protected class Node[B1 >: B](override protected val key: A,
override protected val value: B1) extends ListMap[A, B1] with Serializable {
- /** Returns the number of mappings in this map.
- *
- * @return number of mappings.
- */
- override def size: Int = size0(this, 0)
-
- // to allow tail recursion and prevent stack overflows
- @tailrec private def size0(cur: ListMap[A, B1], acc: Int): Int = if (cur.isEmpty) acc else size0(cur.next, acc + 1)
-
- /** Is this an empty map?
- *
- * @return true, iff the map is empty.
- */
- override def isEmpty: Boolean = false
- /** Retrieves the value which is associated with the given key. This
- * method throws an exception if there is no mapping from the given
- * key to a value.
- *
- * @param k the key
- * @return the value associated with the given key.
- */
- override def apply(k: A): B1 = apply0(this, k)
-
- @tailrec private def apply0(cur: ListMap[A, B1], k: A): B1 =
- if (cur.isEmpty) throw new NoSuchElementException("key not found: "+k)
- else if (k == cur.key) cur.value
- else apply0(cur.next, k)
+ override def size: Int = sizeInternal(this, 0)
+
+ @tailrec private[this] def sizeInternal(cur: ListMap[A, B1], acc: Int): Int =
+ if (cur.isEmpty) acc
+ else sizeInternal(cur.next, acc + 1)
- /** Checks if this map maps `key` to a value and return the
- * value if it exists.
- *
- * @param k the key of the mapping of interest
- * @return the value of the mapping, if it exists
- */
- override def get(k: A): Option[B1] = get0(this, k)
+ override def isEmpty: Boolean = false
+
+ override def apply(k: A): B1 = applyInternal(this, k)
- @tailrec private def get0(cur: ListMap[A, B1], k: A): Option[B1] =
- if (k == cur.key) Some(cur.value)
- else if (cur.next.nonEmpty) get0(cur.next, k) else None
+ @tailrec private[this] def applyInternal(cur: ListMap[A, B1], k: A): B1 =
+ if (cur.isEmpty) throw new NoSuchElementException("key not found: " + k)
+ else if (k == cur.key) cur.value
+ else applyInternal(cur.next, k)
+ override def get(k: A): Option[B1] = getInternal(this, k)
- override def contains(key: A): Boolean = contains0(this, key)
+ @tailrec private[this] def getInternal(cur: ListMap[A, B1], k: A): Option[B1] =
+ if (cur.isEmpty) None
+ else if (k == cur.key) Some(cur.value)
+ else getInternal(cur.next, k)
- @tailrec private def contains0(cur: ListMap[A, B1], k: A): Boolean =
- if (k == cur.key) true
- else if (cur.next.nonEmpty) contains0(cur.next, k)
- else false
+ override def contains(k: A): Boolean = containsInternal(this, k)
+ @tailrec private[this] def containsInternal(cur: ListMap[A, B1], k: A): Boolean =
+ if(cur.isEmpty) false
+ else if (k == cur.key) true
+ else containsInternal(cur.next, k)
- /** This method allows one to create a new map with an additional mapping
- * from `key` to `value`. If the map contains already a mapping for `key`,
- * it will be overridden by this function.
- */
- override def updated [B2 >: B1](k: A, v: B2): ListMap[A, B2] = {
+ override def updated[B2 >: B1](k: A, v: B2): ListMap[A, B2] = {
val m = this - k
new m.Node[B2](k, v)
}
+ override def +[B2 >: B1](kv: (A, B2)): ListMap[A, B2] = {
+ val m = this - kv._1
+ new m.Node[B2](kv._1, kv._2)
+ }
- /** Creates a new mapping without the given `key`.
- * If the map does not contain a mapping for the given key, the
- * method returns the same map.
- */
- override def - (k: A): ListMap[A, B1] = remove0(k, this, Nil)
+ override def -(k: A): ListMap[A, B1] = removeInternal(k, this, Nil)
- @tailrec private def remove0(k: A, cur: ListMap[A, B1], acc: List[ListMap[A, B1]]): ListMap[A, B1] =
- if (cur.isEmpty)
- acc.last
- else if (k == cur.key)
- (cur.next /: acc) {
- case (t, h) => val tt = t; new tt.Node(h.key, h.value) // SI-7459
- }
- else
- remove0(k, cur.next, cur::acc)
+ @tailrec private[this] def removeInternal(k: A, cur: ListMap[A, B1], acc: List[ListMap[A, B1]]): ListMap[A, B1] =
+ if (cur.isEmpty) acc.last
+ else if (k == cur.key) (cur.next /: acc) { case (t, h) => new t.Node(h.key, h.value) }
+ else removeInternal(k, cur.next, cur :: acc)
override protected def next: ListMap[A, B1] = ListMap.this
override def last: (A, B1) = (key, value)
-
override def init: ListMap[A, B1] = next
}
}
diff --git a/src/library/scala/collection/immutable/ListSet.scala b/src/library/scala/collection/immutable/ListSet.scala
index d20e7bc6d2..d9795e9161 100644
--- a/src/library/scala/collection/immutable/ListSet.scala
+++ b/src/library/scala/collection/immutable/ListSet.scala
@@ -12,174 +12,125 @@ package immutable
import generic._
import scala.annotation.tailrec
-import mutable.{Builder, ReusableBuilder}
-/** $factoryInfo
- * @define Coll immutable.ListSet
- * @define coll immutable list set
- * @since 1
- */
+/**
+ * $factoryInfo
+ *
+ * Note that each element insertion takes O(n) time, which means that creating a list set with
+ * n elements will take O(n^2^) time. This makes the builder suitable only for a small number of
+ * elements.
+ *
+ * @since 1
+ * @define Coll ListSet
+ * @define coll list set
+ */
object ListSet extends ImmutableSetFactory[ListSet] {
- /** setCanBuildFromInfo */
- implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, ListSet[A]] = setCanBuildFrom[A]
- override def newBuilder[A]: Builder[A, ListSet[A]] = new ListSetBuilder[A]
+ /**
+ * $setCanBuildFromInfo
+ */
+ implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, ListSet[A]] =
+ setCanBuildFrom[A]
- private object EmptyListSet extends ListSet[Any] { }
+ @SerialVersionUID(5010379588739277132L)
+ private object EmptyListSet extends ListSet[Any]
private[collection] def emptyInstance: ListSet[Any] = EmptyListSet
-
- /** A custom builder because forgetfully adding elements one at
- * a time to a list backed set puts the "squared" in N^2. There is a
- * temporary space cost, but it's improbable a list backed set could
- * become large enough for this to matter given its pricy element lookup.
- *
- * This builder is reusable.
- */
- class ListSetBuilder[Elem](initial: ListSet[Elem]) extends ReusableBuilder[Elem, ListSet[Elem]] {
- def this() = this(empty[Elem])
- protected val elems = (new mutable.ListBuffer[Elem] ++= initial).reverse
- protected val seen = new mutable.HashSet[Elem] ++= initial
-
- def +=(x: Elem): this.type = {
- if (!seen(x)) {
- elems += x
- seen += x
- }
- this
- }
- def clear() = { elems.clear() ; seen.clear() }
- def result() = elems.foldLeft(empty[Elem])(_ unchecked_+ _)
- }
}
-/** This class implements immutable sets using a list-based data
- * structure. Instances of `ListSet` represent
- * empty sets; they can be either created by calling the constructor
- * directly, or by applying the function `ListSet.empty`.
- *
- * @tparam A the type of the elements contained in this list set.
- *
- * @author Matthias Zenger
- * @version 1.0, 09/07/2003
- * @since 1
- * @define Coll immutable.ListSet
- * @define coll immutable list set
- * @define mayNotTerminateInf
- * @define willNotTerminateInf
- */
+/**
+ * This class implements immutable sets using a list-based data structure. List set iterators and
+ * traversal methods visit elements in the order whey were first inserted.
+ *
+ * Elements are stored internally in reversed insertion order, which means the newest element is at
+ * the head of the list. As such, methods such as `head` and `tail` are O(n), while `last` and
+ * `init` are O(1). Other operations, such as inserting or removing entries, are also O(n), which
+ * makes this collection suitable only for a small number of elements.
+ *
+ * Instances of `ListSet` represent empty sets; they can be either created by calling the
+ * constructor directly, or by applying the function `ListSet.empty`.
+ *
+ * @tparam A the type of the elements contained in this list set
+ *
+ * @author Matthias Zenger
+ * @version 1.0, 09/07/2003
+ * @since 1
+ * @define Coll ListSet
+ * @define coll list set
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+@SerialVersionUID(-8417059026623606218L)
sealed class ListSet[A] extends AbstractSet[A]
- with Set[A]
- with GenericSetTemplate[A, ListSet]
- with SetLike[A, ListSet[A]]
- with Serializable{ self =>
+ with Set[A]
+ with GenericSetTemplate[A, ListSet]
+ with SetLike[A, ListSet[A]]
+ with Serializable {
+
override def companion: GenericCompanion[ListSet] = ListSet
- /** Returns the number of elements in this set.
- *
- * @return number of set elements.
- */
override def size: Int = 0
override def isEmpty: Boolean = true
- /** Checks if this set contains element `elem`.
- *
- * @param elem the element to check for membership.
- * @return `'''true'''`, iff `elem` is contained in this set.
- */
def contains(elem: A): Boolean = false
- /** This method creates a new set with an additional element.
- */
- def + (elem: A): ListSet[A] = new Node(elem)
-
- /** `-` can be used to remove a single element.
- */
- def - (elem: A): ListSet[A] = this
+ def +(elem: A): ListSet[A] = new Node(elem)
+ def -(elem: A): ListSet[A] = this
- /** If we are bulk adding elements and desire a runtime measured in
- * sub-interstellar time units, we better find a way to avoid traversing
- * the collection on each element. That's what the custom builder does,
- * so we take the easy way out and add ourselves and the argument to
- * a new builder.
- */
override def ++(xs: GenTraversableOnce[A]): ListSet[A] =
if (xs.isEmpty) this
- else (new ListSet.ListSetBuilder(this) ++= xs.seq).result()
-
- private[ListSet] def unchecked_+(e: A): ListSet[A] = new Node(e)
- private[ListSet] def unchecked_outer: ListSet[A] =
- throw new NoSuchElementException("Empty ListSet has no outer pointer")
-
- /** Creates a new iterator over all elements contained in this set.
- *
- * @throws java.util.NoSuchElementException
- * @return the new iterator
- */
- def iterator: Iterator[A] = new AbstractIterator[A] {
- var that: ListSet[A] = self
- def hasNext = that.nonEmpty
- def next: A =
- if (hasNext) {
- val res = that.head
- that = that.tail
- res
+ else (repr /: xs) (_ + _)
+
+ def iterator: Iterator[A] = {
+ def reverseList = {
+ var curr: ListSet[A] = this
+ var res: List[A] = Nil
+ while (!curr.isEmpty) {
+ res = curr.elem :: res
+ curr = curr.next
}
- else Iterator.empty.next()
+ res
+ }
+ reverseList.iterator
}
- /**
- * @throws java.util.NoSuchElementException
- */
- override def head: A = throw new NoSuchElementException("Set has no elements")
+ protected def elem: A = throw new NoSuchElementException("elem of empty set")
+ protected def next: ListSet[A] = throw new NoSuchElementException("next of empty set")
- /**
- * @throws java.util.NoSuchElementException
- */
- override def tail: ListSet[A] = throw new NoSuchElementException("Next of an empty set")
+ override def toSet[B >: A]: Set[B] = this.asInstanceOf[ListSet[B]]
override def stringPrefix = "ListSet"
- /** Represents an entry in the `ListSet`.
- */
- protected class Node(override val head: A) extends ListSet[A] with Serializable {
- override private[ListSet] def unchecked_outer = self
+ /**
+ * Represents an entry in the `ListSet`.
+ */
+ @SerialVersionUID(-787710309854855049L)
+ protected class Node(override protected val elem: A) extends ListSet[A] with Serializable {
- /** Returns the number of elements in this set.
- *
- * @return number of set elements.
- */
override def size = sizeInternal(this, 0)
- @tailrec private def sizeInternal(n: ListSet[A], acc: Int): Int =
+
+ @tailrec private[this] def sizeInternal(n: ListSet[A], acc: Int): Int =
if (n.isEmpty) acc
- else sizeInternal(n.unchecked_outer, acc + 1)
+ else sizeInternal(n.next, acc + 1)
- /** Checks if this set is empty.
- *
- * @return true, iff there is no element in the set.
- */
override def isEmpty: Boolean = false
- /** Checks if this set contains element `elem`.
- *
- * @param e the element to check for membership.
- * @return `'''true'''`, iff `elem` is contained in this set.
- */
override def contains(e: A) = containsInternal(this, e)
- @tailrec private def containsInternal(n: ListSet[A], e: A): Boolean =
- !n.isEmpty && (n.head == e || containsInternal(n.unchecked_outer, e))
- /** This method creates a new set with an additional element.
- */
+ @tailrec private[this] def containsInternal(n: ListSet[A], e: A): Boolean =
+ !n.isEmpty && (n.elem == e || containsInternal(n.next, e))
+
override def +(e: A): ListSet[A] = if (contains(e)) this else new Node(e)
- /** `-` can be used to remove a single element from a set.
- */
- override def -(e: A): ListSet[A] = if (e == head) self else {
- val tail = self - e; new tail.Node(head)
- }
+ override def -(e: A): ListSet[A] = removeInternal(e, this, Nil)
- override def tail: ListSet[A] = self
- }
+ @tailrec private[this] def removeInternal(k: A, cur: ListSet[A], acc: List[ListSet[A]]): ListSet[A] =
+ if (cur.isEmpty) acc.last
+ else if (k == cur.elem) (cur.next /: acc) { case (t, h) => new t.Node(h.elem) }
+ else removeInternal(k, cur.next, cur :: acc)
- override def toSet[B >: A]: Set[B] = this.asInstanceOf[ListSet[B]]
+ override protected def next: ListSet[A] = ListSet.this
+
+ override def last: A = elem
+ override def init: ListSet[A] = next
+ }
}
diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala
index d3fe367e50..2fe75343d1 100644
--- a/src/library/scala/collection/immutable/Range.scala
+++ b/src/library/scala/collection/immutable/Range.scala
@@ -512,7 +512,7 @@ object Range {
// As there is no appealing default step size for not-really-integral ranges,
// we offer a partially constructed object.
- class Partial[T, U](f: T => U) {
+ class Partial[T, U](private val f: T => U) extends AnyVal {
def by(x: T): U = f(x)
}
diff --git a/src/library/scala/collection/immutable/StringLike.scala b/src/library/scala/collection/immutable/StringLike.scala
index d92db68912..8a9df0e862 100644
--- a/src/library/scala/collection/immutable/StringLike.scala
+++ b/src/library/scala/collection/immutable/StringLike.scala
@@ -100,11 +100,13 @@ self =>
/** Return all lines in this string in an iterator, including trailing
* line end characters.
*
- * The number of strings returned is one greater than the number of line
- * end characters in this string. For an empty string, a single empty
- * line is returned. A line end character is one of
- * - `LF` - line feed (`0x0A` hex)
- * - `FF` - form feed (`0x0C` hex)
+ * This method is analogous to `s.split(EOL).toIterator`,
+ * except that any existing line endings are preserved in the result strings,
+ * and the empty string yields an empty iterator.
+ *
+ * A line end character is one of
+ * - `LF` - line feed (`0x0A`)
+ * - `FF` - form feed (`0x0C`)
*/
def linesWithSeparators: Iterator[String] = new AbstractIterator[String] {
val str = self.toString
@@ -121,14 +123,14 @@ self =>
}
/** Return all lines in this string in an iterator, excluding trailing line
- * end characters, i.e., apply `.stripLineEnd` to all lines
+ * end characters; i.e., apply `.stripLineEnd` to all lines
* returned by `linesWithSeparators`.
*/
def lines: Iterator[String] =
linesWithSeparators map (line => new WrappedString(line).stripLineEnd)
/** Return all lines in this string in an iterator, excluding trailing line
- * end characters, i.e., apply `.stripLineEnd` to all lines
+ * end characters; i.e., apply `.stripLineEnd` to all lines
* returned by `linesWithSeparators`.
*/
@deprecated("Use `lines` instead.","2.11.0")
diff --git a/src/library/scala/io/AnsiColor.scala b/src/library/scala/io/AnsiColor.scala
index 39e2e3b0ca..720049ba8e 100644
--- a/src/library/scala/io/AnsiColor.scala
+++ b/src/library/scala/io/AnsiColor.scala
@@ -1,52 +1,163 @@
package scala
package io
+/** ANSI escape codes providing control over text formatting and color on supporting text terminals.
+ *
+ * ==ANSI Style and Control Codes==
+ *
+ * This group of escape codes provides control over text styling. For example, to turn on reverse video with bold and
+ * then turn off all styling embed these codes,
+ *
+ * {{{
+ * import io.AnsiColor._
+ *
+ * object ColorDemo extends App {
+ *
+ * println(s"$REVERSED${BOLD}Hello 1979!$RESET")
+ * }
+ * }}}
+ *
+ * ==Foreground and Background Colors==
+ *
+ * Embedding ANSI color codes in text output will control the text foreground and background colors.
+ *
+ * <table>
+ * <tr><th style="padding:4px 15px;text-decoration:underline">Foreground</th><th style="width:50%"></th><th style="padding:4px 15px;text-decoration:underline">Background</th></tr>
+ * <tr><td style="padding:4px 15px">BLACK </td><td style="background-color:#000"></td><td style="padding:4px 15px">BLACK_B </td></tr>
+ * <tr><td style="padding:4px 15px">RED </td><td style="background-color:#f00"></td><td style="padding:4px 15px">RED_B </td></tr>
+ * <tr><td style="padding:4px 15px">GREEN </td><td style="background-color:#0f0"></td><td style="padding:4px 15px">GREEN_B </td></tr>
+ * <tr><td style="padding:4px 15px">YELLOW </td><td style="background-color:#ff0"></td><td style="padding:4px 15px">YELLOW_B </td></tr>
+ * <tr><td style="padding:4px 15px">BLUE </td><td style="background-color:#00f"></td><td style="padding:4px 15px">BLUE_B </td></tr>
+ * <tr><td style="padding:4px 15px">MAGENTA</td><td style="background-color:#f0f"></td><td style="padding:4px 15px">MAGENTA_B</td></tr>
+ * <tr><td style="padding:4px 15px">CYAN </td><td style="background-color:#0ff"></td><td style="padding:4px 15px">CYAN_B </td></tr>
+ * <tr><td style="padding:4px 15px">WHITE </td><td style="background-color:#fff"></td><td style="padding:4px 15px">WHITE_B </td></tr>
+ * </table>
+ *
+ * @groupname style-control ANSI Style and Control Codes
+ * @groupprio style-control 101
+ *
+ * @groupname color-black ANSI Black
+ * @groupdesc color-black <table style="width:100%"><tr><td style="background-color:#000">&nbsp;</td></tr></table>
+ * @groupprio color-black 110
+ *
+ * @groupname color-red ANSI Red
+ * @groupdesc color-red <table style="width:100%"><tr><td style="background-color:#f00">&nbsp;</td></tr></table>
+ * @groupprio color-red 120
+ *
+ * @groupname color-green ANSI Green
+ * @groupdesc color-green <table style="width:100%"><tr><td style="background-color:#0f0">&nbsp;</td></tr></table>
+ * @groupprio color-green 130
+ *
+ * @groupname color-yellow ANSI Yellow
+ * @groupdesc color-yellow <table style="width:100%"><tr><td style="background-color:#ff0">&nbsp;</td></tr></table>
+ * @groupprio color-yellow 140
+ *
+ * @groupname color-blue ANSI Blue
+ * @groupdesc color-blue <table style="width:100%"><tr><td style="background-color:#00f">&nbsp;</td></tr></table>
+ * @groupprio color-blue 150
+ *
+ * @groupname color-magenta ANSI Magenta
+ * @groupdesc color-magenta <table style="width:100%"><tr><td style="background-color:#f0f">&nbsp;</td></tr></table>
+ * @groupprio color-magenta 160
+ *
+ * @groupname color-cyan ANSI Cyan
+ * @groupdesc color-cyan <table style="width:100%"><tr><td style="background-color:#0ff">&nbsp;</td></tr></table>
+ * @groupprio color-cyan 170
+ *
+ * @groupname color-white ANSI White
+ * @groupdesc color-white <table style="width:100%"><tr><td style="background-color:#fff">&nbsp;</td></tr></table>
+ * @groupprio color-white 180
+ */
trait AnsiColor {
- /** Foreground color for ANSI black */
+ /** Foreground color for ANSI black
+ * @group color-black
+ */
final val BLACK = "\u001b[30m"
- /** Foreground color for ANSI red */
+ /** Foreground color for ANSI red
+ * @group color-red
+ */
final val RED = "\u001b[31m"
- /** Foreground color for ANSI green */
+ /** Foreground color for ANSI green
+ * @group color-green
+ */
final val GREEN = "\u001b[32m"
- /** Foreground color for ANSI yellow */
+ /** Foreground color for ANSI yellow
+ * @group color-yellow
+ */
final val YELLOW = "\u001b[33m"
- /** Foreground color for ANSI blue */
+ /** Foreground color for ANSI blue
+ * @group color-blue
+ */
final val BLUE = "\u001b[34m"
- /** Foreground color for ANSI magenta */
+ /** Foreground color for ANSI magenta
+ * @group color-magenta
+ */
final val MAGENTA = "\u001b[35m"
- /** Foreground color for ANSI cyan */
+ /** Foreground color for ANSI cyan
+ * @group color-cyan
+ */
final val CYAN = "\u001b[36m"
- /** Foreground color for ANSI white */
+ /** Foreground color for ANSI white
+ * @group color-white
+ */
final val WHITE = "\u001b[37m"
- /** Background color for ANSI black */
+ /** Background color for ANSI black
+ * @group color-black
+ */
final val BLACK_B = "\u001b[40m"
- /** Background color for ANSI red */
+ /** Background color for ANSI red
+ * @group color-red
+ */
final val RED_B = "\u001b[41m"
- /** Background color for ANSI green */
+ /** Background color for ANSI green
+ * @group color-green
+ */
final val GREEN_B = "\u001b[42m"
- /** Background color for ANSI yellow */
+ /** Background color for ANSI yellow
+ * @group color-yellow
+ */
final val YELLOW_B = "\u001b[43m"
- /** Background color for ANSI blue */
+ /** Background color for ANSI blue
+ * @group color-blue
+ */
final val BLUE_B = "\u001b[44m"
- /** Background color for ANSI magenta */
+ /** Background color for ANSI magenta
+ * @group color-magenta
+ */
final val MAGENTA_B = "\u001b[45m"
- /** Background color for ANSI cyan */
+ /** Background color for ANSI cyan
+ * @group color-cyan
+ */
final val CYAN_B = "\u001b[46m"
- /** Background color for ANSI white */
+ /** Background color for ANSI white
+ * @group color-white
+ */
final val WHITE_B = "\u001b[47m"
- /** Reset ANSI styles */
+ /** Reset ANSI styles
+ * @group style-control
+ */
final val RESET = "\u001b[0m"
- /** ANSI bold */
+ /** ANSI bold
+ * @group style-control
+ */
final val BOLD = "\u001b[1m"
- /** ANSI underlines */
+ /** ANSI underlines
+ * @group style-control
+ */
final val UNDERLINED = "\u001b[4m"
- /** ANSI blink */
+ /** ANSI blink
+ * @group style-control
+ */
final val BLINK = "\u001b[5m"
- /** ANSI reversed */
+ /** ANSI reversed
+ * @group style-control
+ */
final val REVERSED = "\u001b[7m"
- /** ANSI invisible */
+ /** ANSI invisible
+ * @group style-control
+ */
final val INVISIBLE = "\u001b[8m"
}
diff --git a/src/library/scala/runtime/java8/JFunction0.java b/src/library/scala/runtime/java8/JFunction0.java
index bdeb7d5f8e..13426cc8af 100644
--- a/src/library/scala/runtime/java8/JFunction0.java
+++ b/src/library/scala/runtime/java8/JFunction0.java
@@ -6,7 +6,7 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction0<R> extends scala.Function0<R> {
+public interface JFunction0<R> extends scala.Function0<R>, java.io.Serializable {
default void $init$() {
};
default void apply$mcV$sp() {
diff --git a/src/library/scala/runtime/java8/JFunction1.java b/src/library/scala/runtime/java8/JFunction1.java
index 2b8580271a..e1f886dad7 100644
--- a/src/library/scala/runtime/java8/JFunction1.java
+++ b/src/library/scala/runtime/java8/JFunction1.java
@@ -6,7 +6,7 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction1<T1, R> extends scala.Function1<T1, R> {
+public interface JFunction1<T1, R> extends scala.Function1<T1, R>, java.io.Serializable {
default void apply$mcVI$sp(int v1) {
apply((T1) scala.runtime.BoxesRunTime.boxToInteger(v1));
}
diff --git a/src/library/scala/runtime/java8/JFunction10.java b/src/library/scala/runtime/java8/JFunction10.java
index 9b9ab4a6c5..f7a25c0df2 100644
--- a/src/library/scala/runtime/java8/JFunction10.java
+++ b/src/library/scala/runtime/java8/JFunction10.java
@@ -6,5 +6,5 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R> extends scala.Function10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R> {
+public interface JFunction10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R> extends scala.Function10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R>, java.io.Serializable {
}
diff --git a/src/library/scala/runtime/java8/JFunction11.java b/src/library/scala/runtime/java8/JFunction11.java
index b24c9a1ed0..9a548b8fc9 100644
--- a/src/library/scala/runtime/java8/JFunction11.java
+++ b/src/library/scala/runtime/java8/JFunction11.java
@@ -6,5 +6,5 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, R> extends scala.Function11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, R> {
+public interface JFunction11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, R> extends scala.Function11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, R>, java.io.Serializable {
}
diff --git a/src/library/scala/runtime/java8/JFunction12.java b/src/library/scala/runtime/java8/JFunction12.java
index 09c90cb7e7..12fb73faaf 100644
--- a/src/library/scala/runtime/java8/JFunction12.java
+++ b/src/library/scala/runtime/java8/JFunction12.java
@@ -6,5 +6,5 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, R> extends scala.Function12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, R> {
+public interface JFunction12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, R> extends scala.Function12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, R>, java.io.Serializable {
}
diff --git a/src/library/scala/runtime/java8/JFunction13.java b/src/library/scala/runtime/java8/JFunction13.java
index e8cc2b53e6..c85c63448a 100644
--- a/src/library/scala/runtime/java8/JFunction13.java
+++ b/src/library/scala/runtime/java8/JFunction13.java
@@ -6,5 +6,5 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, R> extends scala.Function13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, R> {
+public interface JFunction13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, R> extends scala.Function13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, R>, java.io.Serializable {
}
diff --git a/src/library/scala/runtime/java8/JFunction14.java b/src/library/scala/runtime/java8/JFunction14.java
index 327e442b4c..9a578833aa 100644
--- a/src/library/scala/runtime/java8/JFunction14.java
+++ b/src/library/scala/runtime/java8/JFunction14.java
@@ -6,5 +6,5 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, R> extends scala.Function14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, R> {
+public interface JFunction14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, R> extends scala.Function14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, R>, java.io.Serializable {
}
diff --git a/src/library/scala/runtime/java8/JFunction15.java b/src/library/scala/runtime/java8/JFunction15.java
index bd2e3c00da..e993643953 100644
--- a/src/library/scala/runtime/java8/JFunction15.java
+++ b/src/library/scala/runtime/java8/JFunction15.java
@@ -6,5 +6,5 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, R> extends scala.Function15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, R> {
+public interface JFunction15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, R> extends scala.Function15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, R>, java.io.Serializable {
}
diff --git a/src/library/scala/runtime/java8/JFunction16.java b/src/library/scala/runtime/java8/JFunction16.java
index fb961e60ec..a252cb5303 100644
--- a/src/library/scala/runtime/java8/JFunction16.java
+++ b/src/library/scala/runtime/java8/JFunction16.java
@@ -6,5 +6,5 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, R> extends scala.Function16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, R> {
+public interface JFunction16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, R> extends scala.Function16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, R>, java.io.Serializable {
}
diff --git a/src/library/scala/runtime/java8/JFunction17.java b/src/library/scala/runtime/java8/JFunction17.java
index 90a0b1d441..045aa7196f 100644
--- a/src/library/scala/runtime/java8/JFunction17.java
+++ b/src/library/scala/runtime/java8/JFunction17.java
@@ -6,5 +6,5 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, R> extends scala.Function17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, R> {
+public interface JFunction17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, R> extends scala.Function17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, R>, java.io.Serializable {
}
diff --git a/src/library/scala/runtime/java8/JFunction18.java b/src/library/scala/runtime/java8/JFunction18.java
index cac24309e2..ba2bf31206 100644
--- a/src/library/scala/runtime/java8/JFunction18.java
+++ b/src/library/scala/runtime/java8/JFunction18.java
@@ -6,5 +6,5 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, R> extends scala.Function18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, R> {
+public interface JFunction18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, R> extends scala.Function18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, R>, java.io.Serializable {
}
diff --git a/src/library/scala/runtime/java8/JFunction19.java b/src/library/scala/runtime/java8/JFunction19.java
index bbfceac8c3..dde4824293 100644
--- a/src/library/scala/runtime/java8/JFunction19.java
+++ b/src/library/scala/runtime/java8/JFunction19.java
@@ -6,5 +6,5 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, R> extends scala.Function19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, R> {
+public interface JFunction19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, R> extends scala.Function19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, R>, java.io.Serializable {
}
diff --git a/src/library/scala/runtime/java8/JFunction2.java b/src/library/scala/runtime/java8/JFunction2.java
index 1e0293a7e8..548ff60cf6 100644
--- a/src/library/scala/runtime/java8/JFunction2.java
+++ b/src/library/scala/runtime/java8/JFunction2.java
@@ -6,7 +6,7 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction2<T1, T2, R> extends scala.Function2<T1, T2, R> {
+public interface JFunction2<T1, T2, R> extends scala.Function2<T1, T2, R>, java.io.Serializable {
default void apply$mcVII$sp(int v1, int v2) {
apply((T1) scala.runtime.BoxesRunTime.boxToInteger(v1), (T2) scala.runtime.BoxesRunTime.boxToInteger(v2));
}
diff --git a/src/library/scala/runtime/java8/JFunction20.java b/src/library/scala/runtime/java8/JFunction20.java
index 543e657ea7..5505743c20 100644
--- a/src/library/scala/runtime/java8/JFunction20.java
+++ b/src/library/scala/runtime/java8/JFunction20.java
@@ -6,5 +6,5 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, R> extends scala.Function20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, R> {
+public interface JFunction20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, R> extends scala.Function20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, R>, java.io.Serializable {
}
diff --git a/src/library/scala/runtime/java8/JFunction21.java b/src/library/scala/runtime/java8/JFunction21.java
index ecb0d8d287..80e96d3715 100644
--- a/src/library/scala/runtime/java8/JFunction21.java
+++ b/src/library/scala/runtime/java8/JFunction21.java
@@ -6,5 +6,5 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, R> extends scala.Function21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, R> {
+public interface JFunction21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, R> extends scala.Function21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, R>, java.io.Serializable {
}
diff --git a/src/library/scala/runtime/java8/JFunction22.java b/src/library/scala/runtime/java8/JFunction22.java
index 4945cd9db3..45e689458b 100644
--- a/src/library/scala/runtime/java8/JFunction22.java
+++ b/src/library/scala/runtime/java8/JFunction22.java
@@ -6,5 +6,5 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, R> extends scala.Function22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, R> {
+public interface JFunction22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, R> extends scala.Function22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, R>, java.io.Serializable {
}
diff --git a/src/library/scala/runtime/java8/JFunction3.java b/src/library/scala/runtime/java8/JFunction3.java
index ff657dbfd3..6d81bb3a18 100644
--- a/src/library/scala/runtime/java8/JFunction3.java
+++ b/src/library/scala/runtime/java8/JFunction3.java
@@ -6,5 +6,5 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction3<T1, T2, T3, R> extends scala.Function3<T1, T2, T3, R> {
+public interface JFunction3<T1, T2, T3, R> extends scala.Function3<T1, T2, T3, R>, java.io.Serializable {
}
diff --git a/src/library/scala/runtime/java8/JFunction4.java b/src/library/scala/runtime/java8/JFunction4.java
index 246c0d5c72..6c5cd3b61d 100644
--- a/src/library/scala/runtime/java8/JFunction4.java
+++ b/src/library/scala/runtime/java8/JFunction4.java
@@ -6,5 +6,5 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction4<T1, T2, T3, T4, R> extends scala.Function4<T1, T2, T3, T4, R> {
+public interface JFunction4<T1, T2, T3, T4, R> extends scala.Function4<T1, T2, T3, T4, R>, java.io.Serializable {
}
diff --git a/src/library/scala/runtime/java8/JFunction5.java b/src/library/scala/runtime/java8/JFunction5.java
index 1d85c2989e..eca1a406a6 100644
--- a/src/library/scala/runtime/java8/JFunction5.java
+++ b/src/library/scala/runtime/java8/JFunction5.java
@@ -6,5 +6,5 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction5<T1, T2, T3, T4, T5, R> extends scala.Function5<T1, T2, T3, T4, T5, R> {
+public interface JFunction5<T1, T2, T3, T4, T5, R> extends scala.Function5<T1, T2, T3, T4, T5, R>, java.io.Serializable {
}
diff --git a/src/library/scala/runtime/java8/JFunction6.java b/src/library/scala/runtime/java8/JFunction6.java
index 0699c90830..1c9daed5aa 100644
--- a/src/library/scala/runtime/java8/JFunction6.java
+++ b/src/library/scala/runtime/java8/JFunction6.java
@@ -6,5 +6,5 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction6<T1, T2, T3, T4, T5, T6, R> extends scala.Function6<T1, T2, T3, T4, T5, T6, R> {
+public interface JFunction6<T1, T2, T3, T4, T5, T6, R> extends scala.Function6<T1, T2, T3, T4, T5, T6, R>, java.io.Serializable {
}
diff --git a/src/library/scala/runtime/java8/JFunction7.java b/src/library/scala/runtime/java8/JFunction7.java
index 57bc16a066..c1aa130ba1 100644
--- a/src/library/scala/runtime/java8/JFunction7.java
+++ b/src/library/scala/runtime/java8/JFunction7.java
@@ -6,5 +6,5 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction7<T1, T2, T3, T4, T5, T6, T7, R> extends scala.Function7<T1, T2, T3, T4, T5, T6, T7, R> {
+public interface JFunction7<T1, T2, T3, T4, T5, T6, T7, R> extends scala.Function7<T1, T2, T3, T4, T5, T6, T7, R>, java.io.Serializable {
}
diff --git a/src/library/scala/runtime/java8/JFunction8.java b/src/library/scala/runtime/java8/JFunction8.java
index af22b888a3..425e694df8 100644
--- a/src/library/scala/runtime/java8/JFunction8.java
+++ b/src/library/scala/runtime/java8/JFunction8.java
@@ -6,5 +6,5 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction8<T1, T2, T3, T4, T5, T6, T7, T8, R> extends scala.Function8<T1, T2, T3, T4, T5, T6, T7, T8, R> {
+public interface JFunction8<T1, T2, T3, T4, T5, T6, T7, T8, R> extends scala.Function8<T1, T2, T3, T4, T5, T6, T7, T8, R>, java.io.Serializable {
}
diff --git a/src/library/scala/runtime/java8/JFunction9.java b/src/library/scala/runtime/java8/JFunction9.java
index d3c6b26769..21c3c8c6e3 100644
--- a/src/library/scala/runtime/java8/JFunction9.java
+++ b/src/library/scala/runtime/java8/JFunction9.java
@@ -6,5 +6,5 @@
package scala.runtime.java8;
@FunctionalInterface
-public interface JFunction9<T1, T2, T3, T4, T5, T6, T7, T8, T9, R> extends scala.Function9<T1, T2, T3, T4, T5, T6, T7, T8, T9, R> {
+public interface JFunction9<T1, T2, T3, T4, T5, T6, T7, T8, T9, R> extends scala.Function9<T1, T2, T3, T4, T5, T6, T7, T8, T9, R>, java.io.Serializable {
}
diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala
index 8c91242b36..a42a12a6fc 100644
--- a/src/repl/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala
@@ -20,7 +20,6 @@ import scala.tools.nsc.typechecker.{StructuredTypeStrings, TypeStrings}
import scala.tools.nsc.util._
import ScalaClassLoader.URLClassLoader
import scala.tools.nsc.util.Exceptional.unwrap
-import javax.script.{AbstractScriptEngine, Bindings, Compilable, CompiledScript, ScriptContext, ScriptEngine, ScriptEngineFactory, ScriptException}
import java.net.URL
import scala.tools.util.PathResolver
@@ -56,10 +55,11 @@ import scala.tools.util.PathResolver
* @author Moez A. Abdel-Gawad
* @author Lex Spoon
*/
-class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Settings, protected val out: JPrintWriter) extends AbstractScriptEngine with Compilable with Imports with PresentationCompilation {
+class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends Imports with PresentationCompilation {
imain =>
- setBindings(createBindings, ScriptContext.ENGINE_SCOPE)
+ def this(initialSettings: Settings) = this(initialSettings, IMain.defaultOut)
+
object replOutput extends ReplOutput(settings.Yreploutdir) { }
@deprecated("Use replOutput.dir instead", "2.11.0")
@@ -104,13 +104,6 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
finally if (!saved) settings.nowarn.value = false
}
- /** construct an interpreter that reports to Console */
- def this(settings: Settings, out: JPrintWriter) = this(null, settings, out)
- def this(factory: ScriptEngineFactory, settings: Settings) = this(factory, settings, new NewLinePrintWriter(new ConsoleWriter, true))
- def this(settings: Settings) = this(settings, new NewLinePrintWriter(new ConsoleWriter, true))
- def this(factory: ScriptEngineFactory) = this(factory, new Settings())
- def this() = this(new Settings())
-
// the expanded prompt but without color escapes and without leading newline, for purposes of indenting
lazy val formatting = Formatting.forPrompt(replProps.promptText)
lazy val reporter: ReplReporter = new ReplReporter(this)
@@ -464,7 +457,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
pos
}
- private[interpreter] def requestFromLine(line: String, synthetic: Boolean): Either[IR.Result, Request] = {
+ private[interpreter] def requestFromLine(line: String, synthetic: Boolean = false): Either[IR.Result, Request] = {
val content = line
val trees: List[global.Tree] = parse(content) match {
@@ -559,77 +552,8 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
*/
def interpret(line: String): IR.Result = interpret(line, synthetic = false)
def interpretSynthetic(line: String): IR.Result = interpret(line, synthetic = true)
- def interpret(line: String, synthetic: Boolean): IR.Result = compile(line, synthetic) match {
- case Left(result) => result
- case Right(req) => new WrappedRequest(req).loadAndRunReq
- }
-
- private def compile(line: String, synthetic: Boolean): Either[IR.Result, Request] = {
- if (global == null) Left(IR.Error)
- else requestFromLine(line, synthetic) match {
- case Left(result) => Left(result)
- case Right(req) =>
- // null indicates a disallowed statement type; otherwise compile and
- // fail if false (implying e.g. a type error)
- if (req == null || !req.compile) Left(IR.Error) else Right(req)
- }
- }
-
- var code = ""
- var bound = false
- def compiled(script: String): CompiledScript = {
- if (!bound) {
- quietBind("engine" -> this.asInstanceOf[ScriptEngine])
- bound = true
- }
- val cat = code + script
- compile(cat, false) match {
- case Left(result) => result match {
- case IR.Incomplete => {
- code = cat + "\n"
- new CompiledScript {
- def eval(context: ScriptContext): Object = null
- def getEngine: ScriptEngine = IMain.this
- }
- }
- case _ => {
- code = ""
- throw new ScriptException("compile-time error")
- }
- }
- case Right(req) => {
- code = ""
- new WrappedRequest(req)
- }
- }
- }
-
- private class WrappedRequest(val req: Request) extends CompiledScript {
- var recorded = false
-
- /** In Java we would have to wrap any checked exception in the declared
- * ScriptException. Runtime exceptions and errors would be ok and would
- * not need to be caught. So let us do the same in Scala : catch and
- * wrap any checked exception, and let runtime exceptions and errors
- * escape. We could have wrapped runtime exceptions just like other
- * exceptions in ScriptException, this is a choice.
- */
- @throws[ScriptException]
- def eval(context: ScriptContext): Object = {
- val result = req.lineRep.evalEither match {
- case Left(e: RuntimeException) => throw e
- case Left(e: Exception) => throw new ScriptException(e)
- case Left(e) => throw e
- case Right(result) => result.asInstanceOf[Object]
- }
- if (!recorded) {
- recordRequest(req)
- recorded = true
- }
- result
- }
-
- def loadAndRunReq = classLoader.asContext {
+ def interpret(line: String, synthetic: Boolean): IR.Result = {
+ def loadAndRunReq(req: Request) = classLoader.asContext {
val (result, succeeded) = req.loadAndRun
/** To our displeasure, ConsoleReporter offers only printMessage,
@@ -654,12 +578,32 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
}
}
- def getEngine: ScriptEngine = IMain.this
+ compile(line, synthetic) match {
+ case Left(result) => result
+ case Right(req) => loadAndRunReq(req)
+ }
+ }
+
+ // create a Request and compile it
+ private[interpreter] def compile(line: String, synthetic: Boolean): Either[IR.Result, Request] = {
+ if (global == null) Left(IR.Error)
+ else requestFromLine(line, synthetic) match {
+ case Right(null) => Left(IR.Error) // disallowed statement type
+ case Right(req) if !req.compile => Left(IR.Error) // compile error
+ case ok @ Right(req) => ok
+ case err @ Left(result) => err
+ }
}
/** Bind a specified name to a specified value. The name may
* later be used by expressions passed to interpret.
*
+ * A fresh `ReadEvalPrint`, which defines a `line` package, is used to compile
+ * a custom `eval` object that wraps the bound value.
+ *
+ * If the bound value is successfully installed, then bind the name
+ * by interpreting `val name = $line42.$eval.value`.
+ *
* @param name the variable name to bind
* @param boundType the type of the variable, as a string
* @param value the object value to bind to it
@@ -667,22 +611,22 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
*/
def bind(name: String, boundType: String, value: Any, modifiers: List[String] = Nil): IR.Result = {
val bindRep = new ReadEvalPrint()
- bindRep.compile("""
- |object %s {
- | var value: %s = _
- | def set(x: Any) = value = x.asInstanceOf[%s]
+ bindRep.compile(s"""
+ |object ${bindRep.evalName} {
+ | var value: $boundType = _
+ | def set(x: Any) = value = x.asInstanceOf[$boundType]
|}
- """.stripMargin.format(bindRep.evalName, boundType, boundType)
- )
+ """.stripMargin
+ )
bindRep.callEither("set", value) match {
case Left(ex) =>
repldbg("Set failed in bind(%s, %s, %s)".format(name, boundType, value))
repldbg(util.stackTraceString(ex))
IR.Error
-
case Right(_) =>
- val line = "%sval %s = %s.value".format(modifiers map (_ + " ") mkString, name, bindRep.evalPath)
- repldbg("Interpreting: " + line)
+ val mods = if (modifiers.isEmpty) "" else modifiers.mkString("", " ", " ")
+ val line = s"${mods}val $name = ${ bindRep.evalPath }.value"
+ repldbg(s"Interpreting: $line")
interpret(line)
}
}
@@ -1046,31 +990,6 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
override def toString = "Request(line=%s, %s trees)".format(line, trees.size)
}
- def createBindings: Bindings = new IBindings {
- override def put(name: String, value: Object): Object = {
- val n = name.indexOf(":")
- val p: NamedParam = if (n < 0) (name, value) else {
- val nme = name.substring(0, n).trim
- val tpe = name.substring(n + 1).trim
- NamedParamClass(nme, tpe, value)
- }
- if (!p.name.startsWith("javax.script")) bind(p)
- null
- }
- }
-
- @throws[ScriptException]
- def compile(script: String): CompiledScript = eval("new javax.script.CompiledScript { def eval(context: javax.script.ScriptContext): Object = { " + script + " }.asInstanceOf[Object]; def getEngine: javax.script.ScriptEngine = engine }").asInstanceOf[CompiledScript]
-
- @throws[ScriptException]
- def compile(reader: java.io.Reader): CompiledScript = compile(stringFromReader(reader))
-
- @throws[ScriptException]
- def eval(script: String, context: ScriptContext): Object = compiled(script).eval(context)
-
- @throws[ScriptException]
- def eval(reader: java.io.Reader, context: ScriptContext): Object = eval(stringFromReader(reader), context)
-
override def finalize = close
/** Returns the name of the most recent interpreter result.
@@ -1267,54 +1186,9 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
/** Utility methods for the Interpreter. */
object IMain {
- import java.util.Arrays.{ asList => asJavaList }
/** Dummy identifier fragement inserted at the cursor before presentation compilation. Needed to support completion of `global.def<TAB>` */
val DummyCursorFragment = "_CURSOR_"
- class Factory extends ScriptEngineFactory {
- @BeanProperty
- val engineName = "Scala Interpreter"
-
- @BeanProperty
- val engineVersion = "1.0"
-
- @BeanProperty
- val extensions: JList[String] = asJavaList("scala")
-
- @BeanProperty
- val languageName = "Scala"
-
- @BeanProperty
- val languageVersion = scala.util.Properties.versionString
-
- def getMethodCallSyntax(obj: String, m: String, args: String*): String = null
-
- @BeanProperty
- val mimeTypes: JList[String] = asJavaList("application/x-scala")
-
- @BeanProperty
- val names: JList[String] = asJavaList("scala")
-
- def getOutputStatement(toDisplay: String): String = null
-
- def getParameter(key: String): Object = key match {
- case ScriptEngine.ENGINE => engineName
- case ScriptEngine.ENGINE_VERSION => engineVersion
- case ScriptEngine.LANGUAGE => languageName
- case ScriptEngine.LANGUAGE_VERSION => languageVersion
- case ScriptEngine.NAME => names.get(0)
- case _ => null
- }
-
- def getProgram(statements: String*): String = null
-
- def getScriptEngine: ScriptEngine = {
- val settings = new Settings()
- settings.usemanifestcp.value = true
- new IMain(this, settings)
- }
- }
-
// The two name forms this is catching are the two sides of this assignment:
//
// $line3.$read.$iw.$iw.Bippy =
@@ -1366,5 +1240,10 @@ object IMain {
def stripImpl(str: String): String = naming.unmangle(str)
}
+ private[interpreter] def defaultSettings = new Settings()
+ private[scala] def defaultOut = new NewLinePrintWriter(new ConsoleWriter, true)
+
+ /** construct an interpreter that reports to Console */
+ def apply(initialSettings: Settings = defaultSettings, out: JPrintWriter = defaultOut) = new IMain(initialSettings, out)
}
diff --git a/src/repl/scala/tools/nsc/interpreter/Imports.scala b/src/repl/scala/tools/nsc/interpreter/Imports.scala
index fdbd93d862..0cda9c4da3 100644
--- a/src/repl/scala/tools/nsc/interpreter/Imports.scala
+++ b/src/repl/scala/tools/nsc/interpreter/Imports.scala
@@ -127,7 +127,11 @@ trait Imports {
case rh :: rest if !keepHandler(rh.handler) => select(rest, wanted)
case rh :: rest =>
import rh.handler._
- val newWanted = wanted ++ referencedNames -- definedNames -- importedNames
+ val augment = rh match {
+ case ReqAndHandler(_, _: ImportHandler) => referencedNames // for "import a.b", add "a" to names to be resolved
+ case _ => Nil
+ }
+ val newWanted = wanted ++ augment -- definedNames -- importedNames
rh :: select(rest, newWanted)
}
}
@@ -161,6 +165,8 @@ trait Imports {
val tempValLines = mutable.Set[Int]()
for (ReqAndHandler(req, handler) <- reqsToUse) {
val objName = req.lineRep.readPathInstance
+ if (isReplTrace)
+ code.append(ss"// $objName definedNames ${handler.definedNames}, curImps $currentImps\n")
handler match {
case h: ImportHandler if checkHeader(h) =>
header.clear()
@@ -175,21 +181,20 @@ trait Imports {
currentImps ++= x.importedNames
case x if isClassBased =>
- for (imv <- x.definedNames) {
- if (!currentImps.contains(imv)) {
- x match {
- case _: ClassHandler =>
- code.append("import " + objName + req.accessPath + ".`" + imv + "`\n")
- case _ =>
- val valName = req.lineRep.packageName + req.lineRep.readName
- if (!tempValLines.contains(req.lineRep.lineId)) {
- code.append(s"val $valName: ${objName}.type = $objName\n")
- tempValLines += req.lineRep.lineId
- }
- code.append(s"import $valName${req.accessPath}.`$imv`;\n")
- }
- currentImps += imv
+ for (sym <- x.definedSymbols) {
+ maybeWrap(sym.name)
+ x match {
+ case _: ClassHandler =>
+ code.append(s"import ${objName}${req.accessPath}.`${sym.name}`\n")
+ case _ =>
+ val valName = s"${req.lineRep.packageName}${req.lineRep.readName}"
+ if (!tempValLines.contains(req.lineRep.lineId)) {
+ code.append(s"val $valName: ${objName}.type = $objName\n")
+ tempValLines += req.lineRep.lineId
+ }
+ code.append(s"import ${valName}${req.accessPath}.`${sym.name}`\n")
}
+ currentImps += sym.name
}
// For other requests, import each defined name.
// import them explicitly instead of with _, so that
diff --git a/src/repl/scala/tools/nsc/interpreter/Scripted.scala b/src/repl/scala/tools/nsc/interpreter/Scripted.scala
new file mode 100644
index 0000000000..25d359bc0e
--- /dev/null
+++ b/src/repl/scala/tools/nsc/interpreter/Scripted.scala
@@ -0,0 +1,343 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2016 LAMP/EPFL
+ */
+package scala
+package tools.nsc
+package interpreter
+
+import scala.language.dynamics
+
+import scala.beans.BeanProperty
+import scala.collection.JavaConverters._
+import scala.reflect.classTag
+import scala.reflect.internal.util.Position
+import scala.tools.nsc.util.stringFromReader
+import javax.script._, ScriptContext.{ ENGINE_SCOPE, GLOBAL_SCOPE }
+import java.io.{ Closeable, Reader }
+
+/* A REPL adaptor for the javax.script API. */
+class Scripted(@BeanProperty val factory: ScriptEngineFactory, settings: Settings, out: JPrintWriter)
+ extends AbstractScriptEngine with Compilable {
+
+ def createBindings: Bindings = new SimpleBindings
+
+ // dynamic context bound under this name
+ final val ctx = "$ctx"
+
+ // the underlying interpreter, tweaked to handle dynamic bindings
+ val intp = new IMain(settings, out) {
+ import global.{ Name, TermName }
+
+ /* Modify the template to snag definitions from dynamic context.
+ * So object $iw { x + 42 } becomes object $iw { def x = $ctx.x ; x + 42 }
+ */
+ override protected def importsCode(wanted: Set[Name], wrapper: Request#Wrapper, definesClass: Boolean, generousImports: Boolean) = {
+
+ // cull references that can be satisfied from the current dynamic context
+ val contextual = wanted & contextNames
+
+ if (contextual.nonEmpty) {
+ val neededContext = (wanted &~ contextual) + TermName(ctx)
+ val ComputedImports(header, preamble, trailer, path) = super.importsCode(neededContext, wrapper, definesClass, generousImports)
+ val adjusted = contextual.map { n =>
+ val valname = n.decodedName
+ s"""def `$valname` = $ctx.`$valname`
+ def `${valname}_=`(x: Object) = $ctx.`$valname` = x"""
+ }.mkString(preamble, "\n", "\n")
+ ComputedImports(header, adjusted, trailer, path)
+ }
+ else super.importsCode(wanted, wrapper, definesClass, generousImports)
+ }
+
+ // names available in current dynamic context
+ def contextNames: Set[Name] = {
+ val ctx = compileContext
+ val terms = for {
+ scope <- ctx.getScopes.asScala
+ binding <- Option(ctx.getBindings(scope)) map (_.asScala) getOrElse Nil
+ key = binding._1
+ } yield (TermName(key): Name)
+ terms.to[Set]
+ }
+
+ // save first error for exception; console display only if debugging
+ override lazy val reporter: ReplReporter = new ReplReporter(this) {
+ override def display(pos: Position, msg: String, severity: Severity): Unit =
+ if (isReplDebug) super.display(pos, msg, severity)
+ override def error(pos: Position, msg: String): Unit = {
+ if (firstError.isEmpty) firstError = Some((pos, msg))
+ super.error(pos, msg)
+ }
+ override def reset() = { super.reset() ; firstError = None }
+ }
+ }
+ intp.initializeSynchronous()
+
+ var compileContext: ScriptContext = getContext
+
+ val scriptContextRep = new intp.ReadEvalPrint
+
+ def dynamicContext_=(ctx: ScriptContext): Unit = scriptContextRep.callEither("set", ctx)
+
+ def dynamicContext: ScriptContext = scriptContextRep.callEither("value") match {
+ case Right(ctx: ScriptContext) => ctx
+ case Left(e) => throw e
+ case Right(other) => throw new ScriptException(s"Unexpected value for context: $other")
+ }
+
+ if (intp.isInitializeComplete) {
+ // compile the dynamic ScriptContext object holder
+ scriptContextRep compile s"""
+ |import javax.script._
+ |object ${scriptContextRep.evalName} {
+ | var value: ScriptContext = _
+ | def set(x: Any) = value = x.asInstanceOf[ScriptContext]
+ |}
+ """.stripMargin
+ dynamicContext = getContext
+
+ // Bridge dynamic references and script context
+ intp compileString s"""
+ |package scala.tools.nsc.interpreter
+ |import language.dynamics
+ |import javax.script._, ScriptContext.ENGINE_SCOPE
+ |object dynamicBindings extends Dynamic {
+ | def context: ScriptContext = ${ scriptContextRep.evalPath }.value
+ | // $ctx.x retrieves the attribute x
+ | def selectDynamic(field: String): Object = context.getAttribute(field)
+ | // $ctx.x = v
+ | def updateDynamic(field: String)(value: Object) = context.setAttribute(field, value, ENGINE_SCOPE)
+ |}
+ |""".stripMargin
+ intp beQuietDuring {
+ intp interpret s"val $ctx: scala.tools.nsc.interpreter.dynamicBindings.type = scala.tools.nsc.interpreter.dynamicBindings"
+ intp bind ("$engine" -> (this: ScriptEngine with Compilable))
+ }
+ }
+
+ // Set the context for dynamic resolution and run the body.
+ // Defines attributes available for evaluation.
+ // Avoid reflective access if using default context.
+ def withScriptContext[A](context: ScriptContext)(body: => A): A =
+ if (context eq getContext) body else {
+ val saved = dynamicContext
+ dynamicContext = context
+ try body
+ finally dynamicContext = saved
+ }
+ // Defines attributes available for compilation.
+ def withCompileContext[A](context: ScriptContext)(body: => A): A = {
+ val saved = compileContext
+ compileContext = context
+ try body
+ finally compileContext = saved
+ }
+
+ // not obvious that ScriptEngine should accumulate code text
+ private var code = ""
+
+ private var firstError: Option[(Position, String)] = None
+
+ /* All scripts are compiled. The supplied context defines what references
+ * not in REPL history are allowed, though a different context may be
+ * supplied for evaluation of a compiled script.
+ */
+ def compile(script: String, context: ScriptContext): CompiledScript =
+ withCompileContext(context) {
+ val cat = code + script
+ intp.compile(cat, synthetic = false) match {
+ case Right(req) =>
+ code = ""
+ new WrappedRequest(req)
+ case Left(IR.Incomplete) =>
+ code = cat + "\n"
+ new CompiledScript {
+ def eval(context: ScriptContext): Object = null
+ def getEngine: ScriptEngine = Scripted.this
+ }
+ case Left(_) =>
+ code = ""
+ throw firstError map {
+ case (pos, msg) => new ScriptException(msg, script, pos.line, pos.column)
+ } getOrElse new ScriptException("compile-time error")
+ }
+ }
+
+ // documentation
+ //protected var context: ScriptContext
+ //def getContext: ScriptContext = context
+
+ /* Compile with the default context. All references must be resolvable. */
+ @throws[ScriptException]
+ def compile(script: String): CompiledScript = compile(script, context)
+
+ @throws[ScriptException]
+ def compile(reader: Reader): CompiledScript = compile(stringFromReader(reader), context)
+
+ /* Compile and evaluate with the given context. */
+ @throws[ScriptException]
+ def eval(script: String, context: ScriptContext): Object = compile(script, context).eval(context)
+
+ @throws[ScriptException]
+ def eval(reader: Reader, context: ScriptContext): Object = compile(stringFromReader(reader), context).eval(context)
+
+ private class WrappedRequest(val req: intp.Request) extends CompiledScript {
+ var first = true
+
+ private def evalEither(r: intp.Request, ctx: ScriptContext) = {
+ if (ctx.getWriter == null && ctx.getErrorWriter == null && ctx.getReader == null) r.lineRep.evalEither
+ else {
+ val closeables = Array.ofDim[Closeable](2)
+ val w = if (ctx.getWriter == null) Console.out else {
+ val v = new WriterOutputStream(ctx.getWriter)
+ closeables(0) = v
+ v
+ }
+ val e = if (ctx.getErrorWriter == null) Console.err else {
+ val v = new WriterOutputStream(ctx.getErrorWriter)
+ closeables(1) = v
+ v
+ }
+ val in = if (ctx.getReader == null) Console.in else ctx.getReader
+ try {
+ Console.withOut(w) {
+ Console.withErr(e) {
+ Console.withIn(in) {
+ r.lineRep.evalEither
+ }
+ }
+ }
+ } finally {
+ closeables foreach (c => if (c != null) c.close())
+ }
+ }
+ }
+
+ /* First time, cause lazy evaluation of a memoized result.
+ * Subsequently, instantiate a new object for evaluation.
+ * Per the API: Checked exception types thrown by underlying scripting implementations
+ * must be wrapped in instances of ScriptException.
+ */
+ @throws[ScriptException]
+ override def eval(context: ScriptContext) = withScriptContext(context) {
+ if (first) {
+ val result = evalEither(req, context) match {
+ case Left(e: RuntimeException) => throw e
+ case Left(e: Exception) => throw new ScriptException(e)
+ case Left(e) => throw e
+ case Right(result) => result.asInstanceOf[Object]
+ }
+ intp recordRequest req
+ first = false
+ result
+ } else {
+ val defines = req.defines
+ if (defines.isEmpty) {
+ Scripted.this.eval(s"new ${req.lineRep.readPath}")
+ intp recordRequest duplicate(req)
+ null
+ } else {
+ val instance = s"val $$INSTANCE = new ${req.lineRep.readPath};"
+ val newline = (defines map (s => s"val ${s.name} = $$INSTANCE${req.accessPath}.${s.name}")).mkString(instance, ";", ";")
+ val newreq = intp.requestFromLine(newline).right.get
+ val ok = newreq.compile
+
+ val result = evalEither(newreq, context) match {
+ case Left(e: RuntimeException) => throw e
+ case Left(e: Exception) => throw new ScriptException(e)
+ case Left(e) => throw e
+ case Right(result) => intp recordRequest newreq ; result.asInstanceOf[Object]
+ }
+ result
+ }
+ }
+ }
+
+ def duplicate(req: intp.Request) = new intp.Request(req.line, req.trees)
+
+ def getEngine: ScriptEngine = Scripted.this
+ }
+}
+
+object Scripted {
+ import IMain.{ defaultSettings, defaultOut }
+ import java.util.Arrays.asList
+ import scala.util.Properties.versionString
+
+ class Factory extends ScriptEngineFactory {
+ @BeanProperty val engineName = "Scala REPL"
+
+ @BeanProperty val engineVersion = "2.0"
+
+ @BeanProperty val extensions = asList("scala")
+
+ @BeanProperty val languageName = "Scala"
+
+ @BeanProperty val languageVersion = versionString
+
+ @BeanProperty val mimeTypes = asList("application/x-scala")
+
+ @BeanProperty val names = asList("scala")
+
+ def getMethodCallSyntax(obj: String, m: String, args: String*): String = args.mkString(s"$obj.$m(", ", ", ")")
+
+ def getOutputStatement(toDisplay: String): String = s"Console.println($toDisplay)"
+
+ def getParameter(key: String): Object = key match {
+ case ScriptEngine.ENGINE => engineName
+ case ScriptEngine.ENGINE_VERSION => engineVersion
+ case ScriptEngine.LANGUAGE => languageName
+ case ScriptEngine.LANGUAGE_VERSION => languageVersion
+ case ScriptEngine.NAME => names.get(0)
+ case _ => null
+ }
+
+ def getProgram(statements: String*): String = statements.mkString("object Main extends App {\n\t", "\n\t", "\n}")
+
+ def getScriptEngine: ScriptEngine = {
+ val settings = new Settings()
+ settings.usemanifestcp.value = true
+ Scripted(this, settings)
+ }
+ }
+
+ def apply(factory: ScriptEngineFactory = new Factory, settings: Settings = defaultSettings, out: JPrintWriter = defaultOut) = {
+ settings.Yreplclassbased.value = true
+ settings.usejavacp.value = true
+ val s = new Scripted(factory, settings, out)
+ s.setBindings(s.createBindings, ScriptContext.ENGINE_SCOPE)
+ s
+ }
+}
+
+import java.io.Writer
+import java.nio.{ ByteBuffer, CharBuffer }
+import java.nio.charset.{ Charset, CodingErrorAction }
+import CodingErrorAction.{ REPLACE => Replace }
+
+/* An OutputStream that decodes bytes and flushes to the writer. */
+class WriterOutputStream(writer: Writer) extends OutputStream {
+ val decoder = Charset.defaultCharset.newDecoder
+ decoder onMalformedInput Replace
+ decoder onUnmappableCharacter Replace
+
+ val byteBuffer = ByteBuffer.allocate(64)
+ val charBuffer = CharBuffer.allocate(64)
+
+ override def write(b: Int): Unit = {
+ byteBuffer.put(b.toByte)
+ byteBuffer.flip()
+ val result = decoder.decode(byteBuffer, charBuffer, /*eoi=*/ false)
+ if (byteBuffer.remaining == 0) byteBuffer.clear()
+ if (charBuffer.position > 0) {
+ charBuffer.flip()
+ writer write charBuffer.toString
+ charBuffer.clear()
+ }
+ }
+ override def close(): Unit = {
+ decoder.decode(byteBuffer, charBuffer, /*eoi=*/ true)
+ decoder.flush(charBuffer)
+ }
+ override def toString = charBuffer.toString
+}
diff --git a/src/repl/scala/tools/nsc/interpreter/package.scala b/src/repl/scala/tools/nsc/interpreter/package.scala
index 56f1e65376..55949b81a5 100644
--- a/src/repl/scala/tools/nsc/interpreter/package.scala
+++ b/src/repl/scala/tools/nsc/interpreter/package.scala
@@ -88,9 +88,6 @@ package object interpreter extends ReplConfig with ReplStrings {
}
}
- if (filtered.isEmpty)
- return "No implicits have been imported other than those in Predef."
-
filtered foreach {
case (source, syms) =>
p("/* " + syms.size + " implicit members imported from " + source.fullName + " */")
@@ -126,7 +123,14 @@ package object interpreter extends ReplConfig with ReplStrings {
}
p("")
}
- ""
+
+ if (filtered.nonEmpty)
+ "" // side-effects above
+ else if (global.settings.nopredef || global.settings.noimports)
+ "No implicits have been imported."
+ else
+ "No implicits have been imported other than those in Predef."
+
}
def kindCommandInternal(expr: String, verbose: Boolean): Unit = {
@@ -198,13 +202,14 @@ package object interpreter extends ReplConfig with ReplStrings {
}
}
- /* debug assist
+ /* An s-interpolator that uses `stringOf(arg)` instead of `String.valueOf(arg)`. */
private[nsc] implicit class `smart stringifier`(val sc: StringContext) extends AnyVal {
- import StringContext._, runtime.ScalaRunTime.stringOf
+ import StringContext.treatEscapes, scala.runtime.ScalaRunTime.stringOf
def ss(args: Any*): String = sc.standardInterpolator(treatEscapes, args map stringOf)
- } debug assist */
+ }
+ /* Try (body) lastly (more) */
private[nsc] implicit class `try lastly`[A](val t: Try[A]) extends AnyVal {
- private def effect[X](last: =>Unit)(a: X): Try[A] = { last; t }
- def lastly(last: =>Unit): Try[A] = t transform (effect(last) _, effect(last) _)
+ private def effect[X](last: => Unit)(a: X): Try[A] = { last; t }
+ def lastly(last: => Unit): Try[A] = t transform (effect(last) _, effect(last) _)
}
}
diff --git a/src/scaladoc/scala/tools/ant/Scaladoc.scala b/src/scaladoc/scala/tools/ant/Scaladoc.scala
index b38aadd328..63d3b4ce27 100644
--- a/src/scaladoc/scala/tools/ant/Scaladoc.scala
+++ b/src/scaladoc/scala/tools/ant/Scaladoc.scala
@@ -14,8 +14,8 @@ import org.apache.tools.ant.Project
import org.apache.tools.ant.types.{Path, Reference}
import org.apache.tools.ant.util.{FileUtils, GlobPatternMapper}
+import scala.tools.nsc.ScalaDocReporter
import scala.tools.nsc.doc.Settings
-import scala.tools.nsc.reporters.ConsoleReporter
/** An Ant task to document Scala code.
*
@@ -666,7 +666,7 @@ class Scaladoc extends ScalaMatchingTask {
/** Performs the compilation. */
override def execute() = {
val (docSettings, sourceFiles) = initialize
- val reporter = new ConsoleReporter(docSettings)
+ val reporter = new ScalaDocReporter(docSettings)
try {
val docProcessor = new scala.tools.nsc.doc.DocFactory(reporter, docSettings)
docProcessor.document(sourceFiles.map (_.toString))
diff --git a/src/scaladoc/scala/tools/nsc/ScalaDoc.scala b/src/scaladoc/scala/tools/nsc/ScalaDoc.scala
index bd00c27f7b..e266f7beea 100644
--- a/src/scaladoc/scala/tools/nsc/ScalaDoc.scala
+++ b/src/scaladoc/scala/tools/nsc/ScalaDoc.scala
@@ -8,7 +8,8 @@ package scala.tools.nsc
import scala.tools.nsc.doc.DocFactory
import scala.tools.nsc.reporters.ConsoleReporter
-import scala.reflect.internal.util.FakePos
+import scala.reflect.internal.Reporter
+import scala.reflect.internal.util.{ FakePos, NoPosition, Position }
/** The main class for scaladoc, a front-end for the Scala compiler
* that generates documentation from source files.
@@ -38,23 +39,43 @@ class ScalaDoc {
reporter.echo(command.usageMsg)
else
try { new DocFactory(reporter, docSettings) document command.files }
- catch {
- case ex @ FatalError(msg) =>
- if (docSettings.debug.value) ex.printStackTrace()
- reporter.error(null, "fatal error: " + msg)
- }
- finally reporter.printSummary()
+ catch {
+ case ex @ FatalError(msg) =>
+ if (docSettings.debug.value) ex.printStackTrace()
+ reporter.error(null, "fatal error: " + msg)
+ }
+ finally reporter.printSummary()
!reporter.reallyHasErrors
}
}
+/** The Scaladoc reporter adds summary messages to the `ConsoleReporter`
+ *
+ * Use the `summaryX` methods to add unique summarizing message to the end of
+ * the run.
+ */
class ScalaDocReporter(settings: Settings) extends ConsoleReporter(settings) {
+ import scala.collection.mutable.LinkedHashMap
// need to do sometimes lie so that the Global instance doesn't
// trash all the symbols just because there was an error
override def hasErrors = false
def reallyHasErrors = super.hasErrors
+
+ private[this] val delayedMessages: LinkedHashMap[(Position, String), () => Unit] =
+ LinkedHashMap.empty
+
+ /** Eliminates messages if both `pos` and `msg` are equal to existing element */
+ def addDelayedMessage(pos: Position, msg: String, print: () => Unit): Unit =
+ delayedMessages += ((pos, msg) -> print)
+
+ def printDelayedMessages(): Unit = delayedMessages.values.foreach(_.apply())
+
+ override def printSummary(): Unit = {
+ printDelayedMessages()
+ super.printSummary()
+ }
}
object ScalaDoc extends ScalaDoc {
@@ -70,4 +91,20 @@ object ScalaDoc extends ScalaDoc {
def main(args: Array[String]): Unit = sys exit {
if (process(args)) 0 else 1
}
+
+ implicit class SummaryReporter(val rep: Reporter) extends AnyVal {
+ /** Adds print lambda to ScalaDocReporter, executes it on other reporter */
+ private[this] def summaryMessage(pos: Position, msg: String, print: () => Unit): Unit = rep match {
+ case r: ScalaDocReporter => r.addDelayedMessage(pos, msg, print)
+ case _ => print()
+ }
+
+ def summaryEcho(pos: Position, msg: String): Unit = summaryMessage(pos, msg, () => rep.echo(pos, msg))
+ def summaryError(pos: Position, msg: String): Unit = summaryMessage(pos, msg, () => rep.error(pos, msg))
+ def summaryWarning(pos: Position, msg: String): Unit = summaryMessage(pos, msg, () => rep.warning(pos, msg))
+
+ def summaryEcho(msg: String): Unit = summaryEcho(NoPosition, msg)
+ def summaryError(msg: String): Unit = summaryError(NoPosition, msg)
+ def summaryWarning(msg: String): Unit = summaryWarning(NoPosition, msg)
+ }
}
diff --git a/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala b/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala
index fb6c39d7e3..8c646be9c6 100644
--- a/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala
@@ -6,8 +6,8 @@
package scala.tools.nsc
package doc
-import scala.util.control.ControlThrowable
import reporters.Reporter
+import scala.util.control.ControlThrowable
import scala.reflect.internal.util.BatchSourceFile
/** A documentation processor controls the process of generating Scala
@@ -105,7 +105,19 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor
def generate() = {
import doclet._
val docletClass = Class.forName(settings.docgenerator.value) // default is html.Doclet
- val docletInstance = docletClass.newInstance().asInstanceOf[Generator]
+ val docletInstance =
+ docletClass
+ .getConstructors
+ .find { constr =>
+ constr.getParameterTypes.length == 1 &&
+ constr.getParameterTypes.apply(0) == classOf[scala.reflect.internal.Reporter]
+ }
+ .map(_.newInstance(reporter))
+ .getOrElse{
+ reporter.warning(null, "Doclets should be created with the Reporter constructor, otherwise logging reporters will not be shared by the creating parent")
+ docletClass.newInstance()
+ }
+ .asInstanceOf[Generator]
docletInstance match {
case universer: Universer =>
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/Doclet.scala b/src/scaladoc/scala/tools/nsc/doc/html/Doclet.scala
index 541266e4cc..73a854e995 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/Doclet.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/html/Doclet.scala
@@ -7,14 +7,19 @@ package scala.tools.nsc
package doc
package html
+import scala.reflect.internal.Reporter
import doclet._
/** The default doclet used by the scaladoc command line tool
* when no user-provided doclet is provided. */
-class Doclet extends Generator with Universer {
+class Doclet(reporter: Reporter) extends Generator with Universer {
- def generateImpl() {
- new html.HtmlFactory(universe, new ScalaDocReporter(universe.settings)).generate()
- }
+ @deprecated("Doclets should be created with the Reporter constructor. Otherwise logging reporters will not be shared by the creating parent", "2.12.0")
+ def this() = this(null)
+ def generateImpl() =
+ new html.HtmlFactory(
+ universe,
+ if (reporter != null) reporter else new ScalaDocReporter(universe.settings)
+ ).generate()
}
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala b/src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala
index 88b84be65e..62620057cb 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala
@@ -12,12 +12,13 @@ import java.io.{ File => JFile }
import io.{ Streamable, Directory }
import scala.collection._
import page.diagram._
+import scala.reflect.internal.Reporter
/** A class that can generate Scaladoc sites to some fixed root folder.
* @author David Bernard
* @author Gilles Dubochet */
-class HtmlFactory(val universe: doc.Universe, val reporter: ScalaDocReporter) {
- import page.IndexScript
+class HtmlFactory(val universe: doc.Universe, val reporter: Reporter) {
+ import page.{IndexScript, EntityPage}
/** The character encoding to be used for generated Scaladoc sites.
* This value is currently always UTF-8. */
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala b/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala
index 0f37f86b3e..6ad51f4f7e 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala
@@ -13,6 +13,7 @@ import base._
import base.comment._
import model._
+import scala.reflect.internal.Reporter
import scala.xml.NodeSeq
import scala.xml.Elem
import scala.xml.dtd.DocType
@@ -27,7 +28,7 @@ abstract class HtmlPage extends Page { thisPage =>
protected def title: String
/** ScalaDoc reporter for error handling */
- protected def reporter: ScalaDocReporter
+ protected def docletReporter: Reporter
/** The page description */
protected def description: String =
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/Entity.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/Entity.scala
index 836d1b4b7d..9dd2c2184d 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/page/Entity.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/html/page/Entity.scala
@@ -13,6 +13,7 @@ package page
import base._
import base.comment._
+import scala.reflect.internal.Reporter
import scala.collection.mutable
import scala.xml.{NodeSeq, Text, UnprefixedAttribute}
import scala.language.postfixOps
@@ -22,10 +23,12 @@ import model.diagram._
import diagram._
trait EntityPage extends HtmlPage {
+ import ScalaDoc.SummaryReporter
+
def universe: doc.Universe
def generator: DiagramGenerator
def tpl: DocTemplateEntity
- def reporter: ScalaDocReporter
+ def docletReporter: Reporter
override val path = templateToPath(tpl)
@@ -158,8 +161,7 @@ trait EntityPage extends HtmlPage {
val version = universe.settings.docversion.value
if (version.length > "XX.XX.XX-XXX".length) {
- reporter.warning(null,
- s"doc-version ($version) is too long to be displayed in the webview")
+ docletReporter.summaryWarning(s"doc-version ($version) was too long to be displayed in the webview, and will be left out. The max length is: XX.XX.XX-XXX")
""
} else version
}
@@ -1124,12 +1126,12 @@ object EntityPage {
uni: doc.Universe,
gen: DiagramGenerator,
docTpl: DocTemplateEntity,
- rep: ScalaDocReporter
+ rep: Reporter
): EntityPage = new EntityPage {
def universe = uni
def generator = gen
def tpl = docTpl
- def reporter = rep
+ def docletReporter = rep
}
/* Vlad: Lesson learned the hard way: don't put any stateful code that references the model here,
diff --git a/test/files/jvm/interpreter.check b/test/files/jvm/interpreter.check
index ce3c8062d7..9a2162a906 100644
--- a/test/files/jvm/interpreter.check
+++ b/test/files/jvm/interpreter.check
@@ -353,7 +353,7 @@ defined class Term
scala> def f(e: Exp) = e match { // non-exhaustive warning here
case _:Fact => 3
}
-<console>:22: warning: match may not be exhaustive.
+<console>:18: warning: match may not be exhaustive.
It would fail on the following inputs: Exp(), Term()
def f(e: Exp) = e match { // non-exhaustive warning here
^
diff --git a/test/files/jvm/serialization-new.check b/test/files/jvm/serialization-new.check
index cb26446f40..1c5dd4828b 100644
--- a/test/files/jvm/serialization-new.check
+++ b/test/files/jvm/serialization-new.check
@@ -85,12 +85,12 @@ x = List((buffers,20), (layers,2), (title,3))
y = List((buffers,20), (layers,2), (title,3))
x equals y: true, y equals x: true
-x = Map(buffers -> 20, layers -> 2, title -> 3)
-y = Map(buffers -> 20, layers -> 2, title -> 3)
+x = ListMap(buffers -> 20, layers -> 2, title -> 3)
+y = ListMap(buffers -> 20, layers -> 2, title -> 3)
x equals y: true, y equals x: true
-x = ListSet(5, 3)
-y = ListSet(5, 3)
+x = ListSet(3, 5)
+y = ListSet(3, 5)
x equals y: true, y equals x: true
x = Queue(a, b, c)
diff --git a/test/files/jvm/serialization.check b/test/files/jvm/serialization.check
index cb26446f40..1c5dd4828b 100644
--- a/test/files/jvm/serialization.check
+++ b/test/files/jvm/serialization.check
@@ -85,12 +85,12 @@ x = List((buffers,20), (layers,2), (title,3))
y = List((buffers,20), (layers,2), (title,3))
x equals y: true, y equals x: true
-x = Map(buffers -> 20, layers -> 2, title -> 3)
-y = Map(buffers -> 20, layers -> 2, title -> 3)
+x = ListMap(buffers -> 20, layers -> 2, title -> 3)
+y = ListMap(buffers -> 20, layers -> 2, title -> 3)
x equals y: true, y equals x: true
-x = ListSet(5, 3)
-y = ListSet(5, 3)
+x = ListSet(3, 5)
+y = ListSet(3, 5)
x equals y: true, y equals x: true
x = Queue(a, b, c)
diff --git a/test/files/neg/constrs.check b/test/files/neg/constrs.check
index 4f4a12bc13..8a5bd97ae3 100644
--- a/test/files/neg/constrs.check
+++ b/test/files/neg/constrs.check
@@ -7,7 +7,7 @@ constrs.scala:6: error: value u is not a member of object test
constrs.scala:10: error: called constructor's definition must precede calling constructor's definition
def this() = this("abc")
^
-constrs.scala:12: error: called constructor's definition must precede calling constructor's definition
+constrs.scala:12: error: constructor invokes itself
def this(x: Boolean) = this(x)
^
constrs.scala:16: error: type mismatch;
diff --git a/test/files/neg/t4460a.check b/test/files/neg/t4460a.check
index b711e7acb1..7a7618a114 100644
--- a/test/files/neg/t4460a.check
+++ b/test/files/neg/t4460a.check
@@ -1,4 +1,4 @@
-t4460a.scala:6: error: called constructor's definition must precede calling constructor's definition
+t4460a.scala:6: error: constructor invokes itself
def this() = this() // was binding to Predef.<init> !!
^
one error found
diff --git a/test/files/neg/t4460b.check b/test/files/neg/t4460b.check
index f0e703fd10..9a621dbd5c 100644
--- a/test/files/neg/t4460b.check
+++ b/test/files/neg/t4460b.check
@@ -1,4 +1,4 @@
-t4460b.scala:7: error: called constructor's definition must precede calling constructor's definition
+t4460b.scala:7: error: constructor invokes itself
def this() = this() // was binding to Predef.<init> !!
^
one error found
diff --git a/test/files/neg/t9045.check b/test/files/neg/t9045.check
new file mode 100644
index 0000000000..07d0e2dd74
--- /dev/null
+++ b/test/files/neg/t9045.check
@@ -0,0 +1,7 @@
+t9045.scala:3: error: constructor invokes itself
+ def this(axes: Array[Int]) = this(axes)
+ ^
+t9045.scala:6: error: called constructor's definition must precede calling constructor's definition
+ def this(d: Double) = this(d.toLong)
+ ^
+two errors found
diff --git a/test/files/neg/t9045.scala b/test/files/neg/t9045.scala
new file mode 100644
index 0000000000..e6710ab324
--- /dev/null
+++ b/test/files/neg/t9045.scala
@@ -0,0 +1,8 @@
+
+case class AffineImageShape(axes: Seq[Int]) {
+ def this(axes: Array[Int]) = this(axes)
+}
+class X(i: Int) {
+ def this(d: Double) = this(d.toLong)
+ def this(n: Long) = this(n.toInt)
+}
diff --git a/test/files/neg/t9361.check b/test/files/neg/t9361.check
new file mode 100644
index 0000000000..847d137f7d
--- /dev/null
+++ b/test/files/neg/t9361.check
@@ -0,0 +1,11 @@
+t9361.scala:4: error: type mismatch;
+ found : Tc[_$2] where type _$2
+ required: Nothing[]
+ new Foo { def tc = null.asInstanceOf[Tc[_]] }
+ ^
+t9361.scala:4: error: type mismatch;
+ found : Foo[Nothing]
+ required: Foo[Tc]{type T = Nothing}
+ new Foo { def tc = null.asInstanceOf[Tc[_]] }
+ ^
+two errors found
diff --git a/test/files/neg/t9361.scala b/test/files/neg/t9361.scala
new file mode 100644
index 0000000000..b689461e4d
--- /dev/null
+++ b/test/files/neg/t9361.scala
@@ -0,0 +1,5 @@
+abstract class Foo[Tc[_]] { def tc: Tc[_] }
+object Foo {
+ def foo[Tc[_]](): Foo[Tc] { type T = Nothing } =
+ new Foo { def tc = null.asInstanceOf[Tc[_]] }
+}
diff --git a/test/files/pos/t5183.scala b/test/files/pos/t5183.scala
new file mode 100644
index 0000000000..783b8c28dc
--- /dev/null
+++ b/test/files/pos/t5183.scala
@@ -0,0 +1,34 @@
+trait Day
+
+object Test {
+ def foo(t: Int with Day) = t == t
+}
+
+class DayOps(val i: Int with Day) extends AnyVal
+
+case class Test1(d: Int with Day)
+case class Test2(d1: Int with Day, d2: Int with Day)
+
+class User
+class Checkin
+object Example {
+
+ type Tagged[U] = { type Tag = U }
+ type @@[T, U] = T with Tagged[U] // Thanks to @retronym for suggesting this type alias
+
+ class Tagger[U] {
+ def apply[T](t : T) : T @@ U = t.asInstanceOf[T @@ U]
+ }
+ def tag[U] = new Tagger[U]
+
+ // Manual specialization needed here ... specializing apply above doesn't help
+ def tag[U](i : Int) : Int @@ U = i.asInstanceOf[Int @@ U]
+ def tag[U](l : Long) : Long @@ U = l.asInstanceOf[Long @@ U]
+ def tag[U](d : Double) : Double @@ U = d.asInstanceOf[Double @@ U]
+
+ def fetch[A](id: Int @@ A): A = null.asInstanceOf[A]
+
+ def tag[U](arr: Array[Int]):Array[Int @@ U] = arr.asInstanceOf[Array[Int @@ U]]
+
+ tag[User](Array(3, 4, 5)).map(_.toString)
+} \ No newline at end of file
diff --git a/test/files/pos/t7088.scala b/test/files/pos/t7088.scala
new file mode 100644
index 0000000000..de9d1b7040
--- /dev/null
+++ b/test/files/pos/t7088.scala
@@ -0,0 +1,8 @@
+object Example extends App {
+ type Tag[X] = {type Tag = X}
+ type TaggedArray[T] = Array[T] with Tag[Any]
+
+ def method[T: reflect.ClassTag](a: TaggedArray[T], value: T) {a.update(0, value)}
+
+ method(Array(1, 2).asInstanceOf[TaggedArray[Int]], 1)
+}
diff --git a/test/files/pos/t9665.scala b/test/files/pos/t9665.scala
new file mode 100644
index 0000000000..1aa7a5d459
--- /dev/null
+++ b/test/files/pos/t9665.scala
@@ -0,0 +1,7 @@
+
+object | { def unapply(x: (Any, Any)) = Some(x) }
+
+trait Test {
+ def f() = (1,2) match { case 1 `|` 2 => }
+ def g() = 2 match { case 1 | 2 => }
+}
diff --git a/test/files/run/repl-classbased.check b/test/files/run/repl-classbased.check
new file mode 100644
index 0000000000..e11fc170e5
--- /dev/null
+++ b/test/files/run/repl-classbased.check
@@ -0,0 +1,23 @@
+
+scala> case class K(s: String)
+defined class K
+
+scala> class C { implicit val k: K = K("OK?"); override def toString = s"C($k)" }
+defined class C
+
+scala> val c = new C
+c: C = C(K(OK?))
+
+scala> import c.k
+import c.k
+
+scala> implicitly[K]
+res0: K = K(OK?)
+
+scala> val k = 42
+k: Int = 42
+
+scala> k // was K(OK?)
+res1: Int = 42
+
+scala> :quit
diff --git a/test/files/run/repl-classbased.scala b/test/files/run/repl-classbased.scala
new file mode 100644
index 0000000000..595e123159
--- /dev/null
+++ b/test/files/run/repl-classbased.scala
@@ -0,0 +1,22 @@
+
+import scala.tools.partest.ReplTest
+import scala.tools.nsc.Settings
+
+//SI-9740
+object Test extends ReplTest {
+ override def transformSettings(s: Settings): Settings = {
+ s.Yreplclassbased.value = true
+ s
+ }
+
+ def code =
+ """
+case class K(s: String)
+class C { implicit val k: K = K("OK?"); override def toString = s"C($k)" }
+val c = new C
+import c.k
+implicitly[K]
+val k = 42
+k // was K(OK?)
+ """
+}
diff --git a/test/files/run/repl-implicits-nopredef.check b/test/files/run/repl-implicits-nopredef.check
new file mode 100644
index 0000000000..a849801bb4
--- /dev/null
+++ b/test/files/run/repl-implicits-nopredef.check
@@ -0,0 +1,5 @@
+
+scala> :implicits
+No implicits have been imported.
+
+scala> :quit \ No newline at end of file
diff --git a/test/files/run/repl-implicits-nopredef.scala b/test/files/run/repl-implicits-nopredef.scala
new file mode 100644
index 0000000000..8a451b0c52
--- /dev/null
+++ b/test/files/run/repl-implicits-nopredef.scala
@@ -0,0 +1,10 @@
+import scala.tools.partest.ReplTest
+import scala.tools.nsc.Settings
+
+object Test extends ReplTest {
+ override def transformSettings(settings: Settings): Settings = {
+ settings.nopredef.value = true
+ settings
+ }
+ def code = ":implicits"
+}
diff --git a/test/files/run/repl-implicits.check b/test/files/run/repl-implicits.check
new file mode 100644
index 0000000000..6e80cc8799
--- /dev/null
+++ b/test/files/run/repl-implicits.check
@@ -0,0 +1,5 @@
+
+scala> :implicits
+No implicits have been imported other than those in Predef.
+
+scala> :quit \ No newline at end of file
diff --git a/test/files/run/repl-implicits.scala b/test/files/run/repl-implicits.scala
new file mode 100644
index 0000000000..ca8e16e683
--- /dev/null
+++ b/test/files/run/repl-implicits.scala
@@ -0,0 +1,5 @@
+import scala.tools.partest.ReplTest
+
+object Test extends ReplTest {
+ def code = ":implicits"
+}
diff --git a/test/files/run/repl-serialization.scala b/test/files/run/repl-serialization.scala
index 55b7519631..8bc0dd3a8b 100644
--- a/test/files/run/repl-serialization.scala
+++ b/test/files/run/repl-serialization.scala
@@ -36,7 +36,7 @@ object Test {
|extract(() => new AA(x + getX() + y + z + zz + O.apply + u.x))
""".stripMargin
- imain = new IMain(settings)
+ imain = IMain(settings)
println("== evaluating lines")
imain.directBind("extract", "(AnyRef => Unit)", extract)
code.lines.foreach(imain.interpret)
diff --git a/test/files/run/t1500.scala b/test/files/run/t1500.scala
index 30c026f70f..5a2735fbf1 100644
--- a/test/files/run/t1500.scala
+++ b/test/files/run/t1500.scala
@@ -20,7 +20,7 @@ object Test {
val settings = new Settings()
settings.classpath.value = System.getProperty("java.class.path")
- val tool = new interpreter.IMain(settings)
+ val tool = interpreter.IMain(settings)
val global = tool.global
import global._
diff --git a/test/files/run/t3822.scala b/test/files/run/t3822.scala
deleted file mode 100644
index c35804035e..0000000000
--- a/test/files/run/t3822.scala
+++ /dev/null
@@ -1,19 +0,0 @@
-import scala.collection.{ mutable, immutable, generic }
-import immutable.ListSet
-
-object Test {
- def main(args: Array[String]): Unit = {
- val xs = ListSet(-100000 to 100001: _*)
-
- assert(xs.size == 200002)
- assert(xs.sum == 100001)
-
- val ys = ListSet[Int]()
- val ys1 = (1 to 12).grouped(3).foldLeft(ys)(_ ++ _)
- val ys2 = (1 to 12).foldLeft(ys)(_ + _)
-
- assert(ys1 == ys2)
- }
-}
-
-
diff --git a/test/files/run/t5463.scala b/test/files/run/t5463.scala
new file mode 100644
index 0000000000..30b8306156
--- /dev/null
+++ b/test/files/run/t5463.scala
@@ -0,0 +1,21 @@
+import scala.reflect.internal.FatalError
+import scala.tools.partest.DirectTest
+
+object Test extends DirectTest {
+
+ def code = "class A"
+
+ override def show(): Unit = {
+ // Create a broken JAR file and put it on compiler classpath
+ val jarpath = testOutput.path + "/notajar.jar"
+ scala.reflect.io.File(jarpath).writeAll("This isn't really a JAR file")
+
+ val classpath = List(sys.props("partest.lib"), jarpath, testOutput.path) mkString sys.props("path.separator")
+ try {
+ compileString(newCompiler("-cp", classpath, "-d", testOutput.path))(code)
+ throw new Error("Compilation should have failed");
+ } catch {
+ case ex: FatalError => // this is expected
+ }
+ }
+}
diff --git a/test/files/run/t6198.scala b/test/files/run/t6198.scala
index 5aa8f1c1cf..65dbaf8160 100644
--- a/test/files/run/t6198.scala
+++ b/test/files/run/t6198.scala
@@ -1,13 +1,6 @@
import scala.collection.immutable._
object Test extends App {
- // test that ListSet.tail does not use a builder
- // we can't test for O(1) behavior, so the best we can do is to
- // check that ls.tail always returns the same instance
- val ls = ListSet.empty[Int] + 1 + 2
-
- if(ls.tail ne ls.tail)
- println("ListSet.tail should not use a builder!")
// class that always causes hash collisions
case class Collision(value:Int) { override def hashCode = 0 }
diff --git a/test/files/run/t7319.check b/test/files/run/t7319.check
index 4d8429e8f2..31923e7119 100644
--- a/test/files/run/t7319.check
+++ b/test/files/run/t7319.check
@@ -15,21 +15,21 @@ warning: there was one feature warning; re-run with -feature for details
convert: [F[X <: F[X]]](builder: F[_ <: F[_]])Int
scala> convert(Some[Int](0))
-<console>:16: error: no type parameters for method convert: (builder: F[_ <: F[_]])Int exist so that it can be applied to arguments (Some[Int])
+<console>:15: error: no type parameters for method convert: (builder: F[_ <: F[_]])Int exist so that it can be applied to arguments (Some[Int])
--- because ---
argument expression's type is not compatible with formal parameter type;
found : Some[Int]
required: ?F[_$1] forSome { type _$1 <: ?F[_$2] forSome { type _$2 } }
convert(Some[Int](0))
^
-<console>:16: error: type mismatch;
+<console>:15: error: type mismatch;
found : Some[Int]
required: F[_ <: F[_]]
convert(Some[Int](0))
^
scala> Range(1,2).toArray: Seq[_]
-<console>:15: error: polymorphic expression cannot be instantiated to expected type;
+<console>:14: error: polymorphic expression cannot be instantiated to expected type;
found : [B >: Int]Array[B]
required: Seq[_]
Range(1,2).toArray: Seq[_]
diff --git a/test/files/run/t7445.scala b/test/files/run/t7445.scala
deleted file mode 100644
index e4ffeb8e1a..0000000000
--- a/test/files/run/t7445.scala
+++ /dev/null
@@ -1,6 +0,0 @@
-import scala.collection.immutable.ListMap
-
-object Test extends App {
- val a = ListMap(1 -> 1, 2 -> 2, 3 -> 3, 4 -> 4, 5 -> 5);
- require(a.tail == ListMap(2 -> 2, 3 -> 3, 4 -> 4, 5 -> 5));
-}
diff --git a/test/files/run/t7843-jsr223-service.check b/test/files/run/t7843-jsr223-service.check
deleted file mode 100644
index a668df3567..0000000000
--- a/test/files/run/t7843-jsr223-service.check
+++ /dev/null
@@ -1,2 +0,0 @@
-n: Object = 10
-12345678910
diff --git a/test/files/run/t7843-jsr223-service.scala b/test/files/run/t7843-jsr223-service.scala
deleted file mode 100644
index 31112212ea..0000000000
--- a/test/files/run/t7843-jsr223-service.scala
+++ /dev/null
@@ -1,8 +0,0 @@
-import scala.tools.nsc.interpreter.IMain
-
-object Test extends App {
- val engine = new IMain.Factory getScriptEngine()
- engine.asInstanceOf[IMain].settings.usejavacp.value = true
- engine put ("n", 10)
- engine eval "1 to n.asInstanceOf[Int] foreach print"
-}
diff --git a/test/files/run/t7933.check b/test/files/run/t7933.check
deleted file mode 100644
index 317e9677c3..0000000000
--- a/test/files/run/t7933.check
+++ /dev/null
@@ -1,2 +0,0 @@
-hello
-hello
diff --git a/test/files/run/t7933.scala b/test/files/run/t7933.scala
deleted file mode 100644
index b06dffcd80..0000000000
--- a/test/files/run/t7933.scala
+++ /dev/null
@@ -1,11 +0,0 @@
-import scala.tools.nsc.interpreter.IMain
-
-object Test extends App {
- val engine = new IMain.Factory getScriptEngine()
- engine.asInstanceOf[IMain].settings.usejavacp.value = true
- val res2 = engine.asInstanceOf[javax.script.Compilable]
- res2 compile "8" eval()
- val res5 = res2 compile """println("hello") ; 8"""
- res5 eval()
- res5 eval()
-}
diff --git a/test/files/run/t8549.scala b/test/files/run/t8549.scala
index e2d0d335b0..1ce8933efb 100644
--- a/test/files/run/t8549.scala
+++ b/test/files/run/t8549.scala
@@ -79,7 +79,7 @@ object Test extends App {
}
}
- // Generated on 20160328-17:47:35 with Scala version 2.12.0-20160328-174205-d46145c)
+ // Generated on 20160515-00:17:51 with Scala version 2.12.0-SNAPSHOT)
overwrite.foreach(updateComment)
check(Some(1))("rO0ABXNyAApzY2FsYS5Tb21lESLyaV6hi3QCAAFMAAF4dAASTGphdmEvbGFuZy9PYmplY3Q7eHIADHNjYWxhLk9wdGlvbv5pN/3bDmZ0AgAAeHBzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAQ==")
@@ -145,6 +145,8 @@ object Test extends App {
check(immutable.HashSet(1, 2, 3))( "rO0ABXNyADVzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5IYXNoU2V0JFNlcmlhbGl6YXRpb25Qcm94eQAAAAAAAAACAwAAeHB3BAAAAANzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4AAgAAAAJzcQB+AAIAAAADeA==")
// TODO provoke HashSetCollision1
+ check(immutable.ListSet())( "rO0ABXNyADBzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5MaXN0U2V0JEVtcHR5TGlzdFNldCRFiHGwmKwhTAIAAHhyACJzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5MaXN0U2V0izCZaSia0jYCAAB4cA==")
+ check(immutable.ListSet(1))( "rO0ABXNyACdzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5MaXN0U2V0JE5vZGX1EX2lizBAdwIAAkwABiRvdXRlcnQAJExzY2FsYS9jb2xsZWN0aW9uL2ltbXV0YWJsZS9MaXN0U2V0O0wABGVsZW10ABJMamF2YS9sYW5nL09iamVjdDt4cgAic2NhbGEuY29sbGVjdGlvbi5pbW11dGFibGUuTGlzdFNldIswmWkomtI2AgAAeHBzcgAwc2NhbGEuY29sbGVjdGlvbi5pbW11dGFibGUuTGlzdFNldCRFbXB0eUxpc3RTZXQkRYhxsJisIUwCAAB4cQB+AANzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAQ==")
check(immutable.ListMap())( "rO0ABXNyADBzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5MaXN0TWFwJEVtcHR5TGlzdE1hcCSNalsvpBZeDgIAAHhyACJzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5MaXN0TWFwBC1gfIkUSKsCAAB4cA==")
check(immutable.ListMap(1 -> 2))( "rO0ABXNyACdzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5MaXN0TWFwJE5vZGWmciM1Yav+8gIAA0wABiRvdXRlcnQAJExzY2FsYS9jb2xsZWN0aW9uL2ltbXV0YWJsZS9MaXN0TWFwO0wAA2tleXQAEkxqYXZhL2xhbmcvT2JqZWN0O0wABXZhbHVlcQB+AAJ4cgAic2NhbGEuY29sbGVjdGlvbi5pbW11dGFibGUuTGlzdE1hcAQtYHyJFEirAgAAeHBzcgAwc2NhbGEuY29sbGVjdGlvbi5pbW11dGFibGUuTGlzdE1hcCRFbXB0eUxpc3RNYXAkjWpbL6QWXg4CAAB4cQB+AANzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4ABwAAAAI=")
check(immutable.Queue())( "rO0ABXNyACBzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5RdWV1ZZY146W3qSuhAgACTAACaW50ACFMc2NhbGEvY29sbGVjdGlvbi9pbW11dGFibGUvTGlzdDtMAANvdXRxAH4AAXhwc3IAMnNjYWxhLmNvbGxlY3Rpb24uaW1tdXRhYmxlLkxpc3QkU2VyaWFsaXphdGlvblByb3h5AAAAAAAAAAEDAAB4cHNyACxzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5MaXN0U2VyaWFsaXplRW5kJIpcY1v3UwttAgAAeHB4cQB+AAQ=")
diff --git a/test/files/run/t8756.check b/test/files/run/t8756.check
new file mode 100644
index 0000000000..9b9dcafe7d
--- /dev/null
+++ b/test/files/run/t8756.check
@@ -0,0 +1,9 @@
+public Bippy<java.lang.Object> Test.f1(long)
+public Bippy<java.lang.Object> Test.f2(long)
+public Bippy<java.lang.Object> Test.i1(Bippy<java.lang.Object>)
+public Bippy<java.lang.Object> Test.i2(Bippy<java.lang.Object>)
+public int Test.g1(long)
+public int Test.g2(long)
+public java.lang.Object Test.h1(long)
+public java.lang.Object Test.h2(long)
+public static void Test.main(java.lang.String[])
diff --git a/test/files/run/t8756.scala b/test/files/run/t8756.scala
new file mode 100644
index 0000000000..edd243473a
--- /dev/null
+++ b/test/files/run/t8756.scala
@@ -0,0 +1,22 @@
+trait Bippy[A]
+
+class Test {
+ type T1 = Long
+ type T2 = Long { type Tag = Nothing }
+
+ def f1(t: T1): Bippy[Object] = ???
+ def f2(t: T2): Bippy[Object] = ???
+ def g1(t: T1): Int = ???
+ def g2(t: T2): Int = ???
+ def h1(t: T1): Object = ???
+ def h2(t: T2): Object = ???
+ def i1(t: Bippy[T1]): Bippy[T1] = ???
+ def i2(t: Bippy[T2]): Bippy[T2] = ???
+
+}
+
+object Test {
+ def main(args: Array[String]) {
+ println(classOf[Test].getDeclaredMethods.map(_.toGenericString).toList.sorted.mkString("\n"))
+ }
+}
diff --git a/test/files/run/trait-static-forwarder.check b/test/files/run/trait-static-forwarder.check
new file mode 100644
index 0000000000..d81cc0710e
--- /dev/null
+++ b/test/files/run/trait-static-forwarder.check
@@ -0,0 +1 @@
+42
diff --git a/test/files/run/trait-static-forwarder/Test.java b/test/files/run/trait-static-forwarder/Test.java
new file mode 100644
index 0000000000..89012c0162
--- /dev/null
+++ b/test/files/run/trait-static-forwarder/Test.java
@@ -0,0 +1,5 @@
+public final class Test {
+ public static void main(String... args) {
+ System.out.println(T.foo());
+ }
+}
diff --git a/test/files/run/trait-static-forwarder/forwarders.scala b/test/files/run/trait-static-forwarder/forwarders.scala
new file mode 100644
index 0000000000..d6ee9a081d
--- /dev/null
+++ b/test/files/run/trait-static-forwarder/forwarders.scala
@@ -0,0 +1,5 @@
+trait T
+
+object T {
+ def foo = 42
+}
diff --git a/test/junit/scala/BoxUnboxTest.scala b/test/junit/scala/BoxUnboxTest.scala
deleted file mode 100644
index 162d805a6b..0000000000
--- a/test/junit/scala/BoxUnboxTest.scala
+++ /dev/null
@@ -1,119 +0,0 @@
-package scala
-
-import org.junit.Test
-import org.junit.Assert._
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-import scala.tools.testing.AssertUtil._
-
-@RunWith(classOf[JUnit4])
-class BoxUnboxTest {
- def genericNull[T] = null.asInstanceOf[T] // allowed, see SI-4437, point 2
-
- @Test
- def boxUnboxInt(): Unit = {
- val b = new Integer(1)
- val u = 1
-
- assertEquals(1.toInt, u)
-
- assertEquals(Predef.int2Integer(1), b)
- assertEquals(1: Integer, b)
- assertEquals(Int.box(1), b)
- assertEquals(1.asInstanceOf[Object], b)
-
- assertThrows[ClassCastException]("".asInstanceOf[Integer])
-
- assertEquals(Predef.Integer2int(b), u)
- assertEquals(b: Int, u)
- assertEquals(Int.unbox(b), u)
- assertEquals(b.asInstanceOf[Int], u)
- assertEquals(b.intValue, u)
- assertEquals(b.toInt, u)
- intWrapper(b).toInt
-
- assertThrows[ClassCastException](Int.unbox(""))
- assertThrows[ClassCastException]("".asInstanceOf[Int])
-
- // null unboxing in various positions
-
- val n1 = Int.unbox(null)
- assertEquals(n1, 0)
- val n2 = Predef.Integer2int(null)
- assertEquals(n2, 0)
- val n3 = (null: Integer): Int
- assertEquals(n3, 0)
- val n4 = null.asInstanceOf[Int]
- assertEquals(n4, 0)
- val n5 = null.asInstanceOf[Int] == 0
- assertTrue(n5)
- val n6 = null.asInstanceOf[Int] == null // SI-9671 -- should be false, but is true
- assertThrows[AssertionError](assertFalse(n6)) // should not throw
- val n7 = null.asInstanceOf[Int] != 0
- assertFalse(n7)
- val n8 = null.asInstanceOf[Int] != null // SI-9671 -- should be true, but is false
- assertThrows[AssertionError](assertTrue(n8)) // should not throw
-
- val mp = new java.util.HashMap[Int, Int]
- val n9 = mp.get(0)
- assertEquals(n9, 0)
- val n10 = mp.get(0) == null // SI-602 -- maybe related to SI-9671 (test above)?
- assertThrows[AssertionError](assertFalse(n10)) // should not throw
-
- def f(a: Any) = "" + a
- val n11 = f(null.asInstanceOf[Int]) // "null", should be "0". probably same cause as SI-602.
- assertThrows[AssertionError](assertEquals(n11, "0")) // should not throw
-
- def n12 = genericNull[Int]
- assertEquals(n12, 0)
- }
-
- @Test
- def numericConversions(): Unit = {
- val i1 = 1L.asInstanceOf[Int]
- assertEquals(i1, 1)
- assertThrows[ClassCastException] {
- val i2 = (1L: Any).asInstanceOf[Int] // SI-1448, should not throw. see also SI-4437 point 1.
- assertEquals(i2, 1)
- }
- }
-
- @Test
- def boxUnboxBoolean(): Unit = {
- val n1 = Option(null.asInstanceOf[Boolean]) // SI-7397 -- should be Some(false), but is None
- assertThrows[AssertionError](assertEquals(n1, Some(false))) // should not throw
- }
-
- @Test
- def boxUnboxUnit(): Unit = {
- // should not use assertEquals in this test: it takes two Object parameters. normally, Unit does
- // not conform to Object, but for Java-defined methods scalac makes an exception and treats them
- // as Any. passing a Unit as Any makes the compiler go through another layer of boxing, so it
- // can hide some bugs (where we actually have a null, but the compiler makes it a ()).
-
- var v = 0
- def eff() = { v = 1 }
- def chk() = { assert(v == 1); v = 0 }
-
- val b = runtime.BoxedUnit.UNIT
-
- assert(eff() == b); chk()
- assert(Unit.box(eff()) == b); chk()
- assert(().asInstanceOf[Object] == b)
-
- Unit.unbox({eff(); b}); chk()
- Unit.unbox({eff(); null}); chk()
- assertThrows[ClassCastException](Unit.unbox({eff(); ""})); chk()
-
- val n1 = null.asInstanceOf[Unit] // SI-9066: should be UNIT, but currently null
- assertThrows[AssertionError](assert(n1 == b)) // should not throw
-
- val n2 = null.asInstanceOf[Unit] == b // SI-9066: should be true, but currently false
- assertThrows[AssertionError](assert(n2)) // should not throw
-
- def f(a: Any) = "" + a
- val n3 = f(null.asInstanceOf[Unit]) // "null", should be "()". probably same cause as SI-602.
- assertThrows[AssertionError](assertEquals(n3, "()")) // should not throw
- }
-}
diff --git a/test/junit/scala/PartialFunctionSerializationTest.scala b/test/junit/scala/PartialFunctionSerializationTest.scala
index d525b045cd..2019e3a425 100644
--- a/test/junit/scala/PartialFunctionSerializationTest.scala
+++ b/test/junit/scala/PartialFunctionSerializationTest.scala
@@ -7,24 +7,18 @@ import org.junit.runners.JUnit4
@RunWith(classOf[JUnit4])
class PartialFunctionSerializationTest {
- val pf1: PartialFunction[Int, Int] = {
- case n if n > 0 => 1
- }
-
- val pf2: PartialFunction[Int, Int] = {
- case n if n <= 0 => 2
- }
+ val pf1: PartialFunction[Int, Int] = { case n if n > 0 => 1 }
+ val pf2: PartialFunction[Int, Int] = { case n if n <= 0 => 2 }
- private def assertSerializable[A,B](fn: A => B) = {
+ private def assertSerializable[A,B](fn: A => B): Unit = {
import java.io._
-
new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(fn)
}
- @Test def canSerializeLiteral= assertSerializable(pf1)
+ @Test def canSerializeLiteral = assertSerializable(pf1)
- @Test def canSerializeLifted= assertSerializable(pf1.lift)
+ @Test def canSerializeLifted = assertSerializable(pf1.lift)
@Test def canSerializeOrElse = assertSerializable(pf1 orElse pf2)
diff --git a/test/junit/scala/collection/convert/NullSafetyTest.scala b/test/junit/scala/collection/convert/NullSafetyTest.scala
deleted file mode 100644
index 173568408c..0000000000
--- a/test/junit/scala/collection/convert/NullSafetyTest.scala
+++ /dev/null
@@ -1,279 +0,0 @@
-package scala.collection.convert
-
-import java.{util => ju, lang => jl}
-import ju.{concurrent => juc}
-
-import org.junit.Test
-import org.junit.experimental.runners.Enclosed
-import org.junit.runner.RunWith
-
-import collection.convert.ImplicitConversions._
-import scala.collection.JavaConverters._
-import scala.collection.{mutable, concurrent}
-
-@RunWith(classOf[Enclosed])
-object NullSafetyTest {
-
- /*
- * Pertinent: SI-9113
- * Tests to insure that wrappers return null instead of wrapping it as a collection
- */
-
- class ToScala {
-
- @Test def testIteratorWrapping(): Unit = {
- val nullJIterator: ju.Iterator[AnyRef] = null
- val iterator: Iterator[AnyRef] = nullJIterator
-
- assert(iterator == null)
- }
-
- @Test def testEnumerationWrapping(): Unit = {
- val nullJEnumeration: ju.Enumeration[AnyRef] = null
- val enumeration: Iterator[AnyRef] = nullJEnumeration
-
- assert(enumeration == null)
- }
-
- @Test def testIterableWrapping(): Unit = {
- val nullJIterable: jl.Iterable[AnyRef] = null
- val iterable: Iterable[AnyRef] = nullJIterable
-
- assert(iterable == null)
- }
-
- @Test def testCollectionWrapping(): Unit = {
- val nullJCollection: ju.Collection[AnyRef] = null
- val collection: Iterable[AnyRef] = nullJCollection
-
- assert(collection == null)
- }
-
- @Test def testBufferWrapping(): Unit = {
- val nullJList: ju.List[AnyRef] = null
- val buffer: mutable.Buffer[AnyRef] = nullJList
-
- assert(buffer == null)
- }
-
- @Test def testSetWrapping(): Unit = {
- val nullJSet: ju.Set[AnyRef] = null
- val set: mutable.Set[AnyRef] = nullJSet
-
- assert(set == null)
- }
-
- @Test def testMapWrapping(): Unit = {
- val nullJMap: ju.Map[AnyRef, AnyRef] = null
- val map: mutable.Map[AnyRef, AnyRef] = nullJMap
-
- assert(map == null)
- }
-
- @Test def testConcurrentMapWrapping(): Unit = {
- val nullJConMap: juc.ConcurrentMap[AnyRef, AnyRef] = null
- val conMap: concurrent.Map[AnyRef, AnyRef] = nullJConMap
-
- assert(conMap == null)
- }
-
- @Test def testDictionaryWrapping(): Unit = {
- val nullJDict: ju.Dictionary[AnyRef, AnyRef] = null
- val dict: mutable.Map[AnyRef, AnyRef] = nullJDict
-
- assert(dict == null)
- }
-
-
- @Test def testPropertyWrapping(): Unit = {
- val nullJProps: ju.Properties = null
- val props: mutable.Map[String, String] = nullJProps
-
- assert(props == null)
- }
-
- @Test def testIteratorDecoration(): Unit = {
- val nullJIterator: ju.Iterator[AnyRef] = null
-
- assert(nullJIterator.asScala == null)
- }
-
- @Test def testEnumerationDecoration(): Unit = {
- val nullJEnumeration: ju.Enumeration[AnyRef] = null
-
- assert(nullJEnumeration.asScala == null)
- }
-
- @Test def testIterableDecoration(): Unit = {
- val nullJIterable: jl.Iterable[AnyRef] = null
-
- assert(nullJIterable.asScala == null)
- }
-
- @Test def testCollectionDecoration(): Unit = {
- val nullJCollection: ju.Collection[AnyRef] = null
-
- assert(nullJCollection.asScala == null)
- }
-
- @Test def testBufferDecoration(): Unit = {
- val nullJBuffer: ju.List[AnyRef] = null
-
- assert(nullJBuffer.asScala == null)
- }
-
- @Test def testSetDecoration(): Unit = {
- val nullJSet: ju.Set[AnyRef] = null
-
- assert(nullJSet.asScala == null)
- }
-
- @Test def testMapDecoration(): Unit = {
- val nullJMap: ju.Map[AnyRef, AnyRef] = null
-
- assert(nullJMap.asScala == null)
- }
-
- @Test def testConcurrentMapDecoration(): Unit = {
- val nullJConMap: juc.ConcurrentMap[AnyRef, AnyRef] = null
-
- assert(nullJConMap.asScala == null)
- }
-
- @Test def testDictionaryDecoration(): Unit = {
- val nullJDict: ju.Dictionary[AnyRef, AnyRef] = null
-
- assert(nullJDict.asScala == null)
- }
-
- @Test def testPropertiesDecoration(): Unit = {
- val nullJProperties: ju.Properties = null
-
- assert(nullJProperties.asScala == null)
- }
- }
-
- class ToJava {
-
- @Test def testIteratorWrapping(): Unit = {
- val nullIterator: Iterator[AnyRef] = null
- val jIterator: ju.Iterator[AnyRef] = nullIterator
-
- assert(jIterator == null)
- }
-
- @Test def testEnumerationWrapping(): Unit = {
- val nullEnumeration: Iterator[AnyRef] = null
- val enumeration: ju.Iterator[AnyRef] = nullEnumeration
-
- assert(enumeration == null)
- }
-
- @Test def testIterableWrapping(): Unit = {
- val nullIterable: Iterable[AnyRef] = null
- val iterable: jl.Iterable[AnyRef] = asJavaIterable(nullIterable)
-
- assert(iterable == null)
- }
-
- @Test def testCollectionWrapping(): Unit = {
- val nullCollection: Iterable[AnyRef] = null
- val collection: ju.Collection[AnyRef] = nullCollection
-
- assert(collection == null)
- }
-
- @Test def testBufferWrapping(): Unit = {
- val nullList: mutable.Buffer[AnyRef] = null
- val buffer: ju.List[AnyRef] = nullList
-
- assert(buffer == null)
- }
-
- @Test def testSetWrapping(): Unit = {
- val nullSet: mutable.Set[AnyRef] = null
- val set: ju.Set[AnyRef] = nullSet
-
- assert(set == null)
- }
-
- @Test def testMapWrapping(): Unit = {
- val nullMap: mutable.Map[AnyRef, AnyRef] = null
- val map: ju.Map[AnyRef, AnyRef] = nullMap
-
- assert(map == null)
- }
-
- @Test def testConcurrentMapWrapping(): Unit = {
- val nullConMap: concurrent.Map[AnyRef, AnyRef] = null
- val conMap: juc.ConcurrentMap[AnyRef, AnyRef] = nullConMap
-
- assert(conMap == null)
- }
-
- @Test def testDictionaryWrapping(): Unit = {
- val nullDict: mutable.Map[AnyRef, AnyRef] = null
- val dict: ju.Dictionary[AnyRef, AnyRef] = nullDict
-
- assert(dict == null)
- }
-
- // Implicit conversion to ju.Properties is not available
-
- @Test def testIteratorDecoration(): Unit = {
- val nullIterator: Iterator[AnyRef] = null
-
- assert(nullIterator.asJava == null)
- }
-
- @Test def testEnumerationDecoration(): Unit = {
- val nullEnumeration: Iterator[AnyRef] = null
-
- assert(nullEnumeration.asJavaEnumeration == null)
- }
-
- @Test def testIterableDecoration(): Unit = {
- val nullIterable: Iterable[AnyRef] = null
-
- assert(nullIterable.asJava == null)
- }
-
- @Test def testCollectionDecoration(): Unit = {
- val nullCollection: Iterable[AnyRef] = null
-
- assert(nullCollection.asJavaCollection == null)
- }
-
- @Test def testBufferDecoration(): Unit = {
- val nullBuffer: mutable.Buffer[AnyRef] = null
-
- assert(nullBuffer.asJava == null)
- }
-
- @Test def testSetDecoration(): Unit = {
- val nullSet: Set[AnyRef] = null
-
- assert(nullSet.asJava == null)
- }
-
- @Test def testMapDecoration(): Unit = {
- val nullMap: mutable.Map[AnyRef, AnyRef] = null
-
- assert(nullMap.asJava == null)
- }
-
- @Test def testConcurrentMapDecoration(): Unit = {
- val nullConMap: concurrent.Map[AnyRef, AnyRef] = null
-
- assert(nullConMap.asJava == null)
- }
-
- @Test def testDictionaryDecoration(): Unit = {
- val nullDict: mutable.Map[AnyRef, AnyRef] = null
-
- assert(nullDict.asJavaDictionary == null)
- }
-
- // Decorator conversion to ju.Properties is not available
- }
-}
diff --git a/test/junit/scala/collection/convert/NullSafetyToJavaTest.scala b/test/junit/scala/collection/convert/NullSafetyToJavaTest.scala
new file mode 100644
index 0000000000..da0513ed8a
--- /dev/null
+++ b/test/junit/scala/collection/convert/NullSafetyToJavaTest.scala
@@ -0,0 +1,138 @@
+package scala.collection.convert
+
+import java.util.{concurrent => juc}
+import java.{lang => jl, util => ju}
+
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+import scala.collection.JavaConverters._
+import scala.collection.convert.ImplicitConversions._
+import scala.collection.{concurrent, mutable}
+
+// SI-9113: tests to insure that wrappers return null instead of wrapping it as a collection
+
+@RunWith(classOf[JUnit4])
+class NullSafetyToJavaTest {
+ @Test def testIteratorWrapping(): Unit = {
+ val nullIterator: Iterator[AnyRef] = null
+ val jIterator: ju.Iterator[AnyRef] = nullIterator
+
+ assert(jIterator == null)
+ }
+
+ @Test def testEnumerationWrapping(): Unit = {
+ val nullEnumeration: Iterator[AnyRef] = null
+ val enumeration: ju.Iterator[AnyRef] = nullEnumeration
+
+ assert(enumeration == null)
+ }
+
+ @Test def testIterableWrapping(): Unit = {
+ val nullIterable: Iterable[AnyRef] = null
+ val iterable: jl.Iterable[AnyRef] = asJavaIterable(nullIterable)
+
+ assert(iterable == null)
+ }
+
+ @Test def testCollectionWrapping(): Unit = {
+ val nullCollection: Iterable[AnyRef] = null
+ val collection: ju.Collection[AnyRef] = nullCollection
+
+ assert(collection == null)
+ }
+
+ @Test def testBufferWrapping(): Unit = {
+ val nullList: mutable.Buffer[AnyRef] = null
+ val buffer: ju.List[AnyRef] = nullList
+
+ assert(buffer == null)
+ }
+
+ @Test def testSetWrapping(): Unit = {
+ val nullSet: mutable.Set[AnyRef] = null
+ val set: ju.Set[AnyRef] = nullSet
+
+ assert(set == null)
+ }
+
+ @Test def testMapWrapping(): Unit = {
+ val nullMap: mutable.Map[AnyRef, AnyRef] = null
+ val map: ju.Map[AnyRef, AnyRef] = nullMap
+
+ assert(map == null)
+ }
+
+ @Test def testConcurrentMapWrapping(): Unit = {
+ val nullConMap: concurrent.Map[AnyRef, AnyRef] = null
+ val conMap: juc.ConcurrentMap[AnyRef, AnyRef] = nullConMap
+
+ assert(conMap == null)
+ }
+
+ @Test def testDictionaryWrapping(): Unit = {
+ val nullDict: mutable.Map[AnyRef, AnyRef] = null
+ val dict: ju.Dictionary[AnyRef, AnyRef] = nullDict
+
+ assert(dict == null)
+ }
+
+ // Implicit conversion to ju.Properties is not available
+
+ @Test def testIteratorDecoration(): Unit = {
+ val nullIterator: Iterator[AnyRef] = null
+
+ assert(nullIterator.asJava == null)
+ }
+
+ @Test def testEnumerationDecoration(): Unit = {
+ val nullEnumeration: Iterator[AnyRef] = null
+
+ assert(nullEnumeration.asJavaEnumeration == null)
+ }
+
+ @Test def testIterableDecoration(): Unit = {
+ val nullIterable: Iterable[AnyRef] = null
+
+ assert(nullIterable.asJava == null)
+ }
+
+ @Test def testCollectionDecoration(): Unit = {
+ val nullCollection: Iterable[AnyRef] = null
+
+ assert(nullCollection.asJavaCollection == null)
+ }
+
+ @Test def testBufferDecoration(): Unit = {
+ val nullBuffer: mutable.Buffer[AnyRef] = null
+
+ assert(nullBuffer.asJava == null)
+ }
+
+ @Test def testSetDecoration(): Unit = {
+ val nullSet: Set[AnyRef] = null
+
+ assert(nullSet.asJava == null)
+ }
+
+ @Test def testMapDecoration(): Unit = {
+ val nullMap: mutable.Map[AnyRef, AnyRef] = null
+
+ assert(nullMap.asJava == null)
+ }
+
+ @Test def testConcurrentMapDecoration(): Unit = {
+ val nullConMap: concurrent.Map[AnyRef, AnyRef] = null
+
+ assert(nullConMap.asJava == null)
+ }
+
+ @Test def testDictionaryDecoration(): Unit = {
+ val nullDict: mutable.Map[AnyRef, AnyRef] = null
+
+ assert(nullDict.asJavaDictionary == null)
+ }
+
+ // Decorator conversion to ju.Properties is not available
+}
diff --git a/test/junit/scala/collection/convert/NullSafetyToScalaTest.scala b/test/junit/scala/collection/convert/NullSafetyToScalaTest.scala
new file mode 100644
index 0000000000..9b6d366faf
--- /dev/null
+++ b/test/junit/scala/collection/convert/NullSafetyToScalaTest.scala
@@ -0,0 +1,148 @@
+package scala.collection.convert
+
+import java.util.{concurrent => juc}
+import java.{lang => jl, util => ju}
+
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+import scala.collection.JavaConverters._
+import scala.collection.convert.ImplicitConversions._
+import scala.collection.{concurrent, mutable}
+
+// SI-9113: tests to insure that wrappers return null instead of wrapping it as a collection
+
+@RunWith(classOf[JUnit4])
+class NullSafetyToScalaTest {
+ @Test def testIteratorWrapping(): Unit = {
+ val nullJIterator: ju.Iterator[AnyRef] = null
+ val iterator: Iterator[AnyRef] = nullJIterator
+
+ assert(iterator == null)
+ }
+
+ @Test def testEnumerationWrapping(): Unit = {
+ val nullJEnumeration: ju.Enumeration[AnyRef] = null
+ val enumeration: Iterator[AnyRef] = nullJEnumeration
+
+ assert(enumeration == null)
+ }
+
+ @Test def testIterableWrapping(): Unit = {
+ val nullJIterable: jl.Iterable[AnyRef] = null
+ val iterable: Iterable[AnyRef] = nullJIterable
+
+ assert(iterable == null)
+ }
+
+ @Test def testCollectionWrapping(): Unit = {
+ val nullJCollection: ju.Collection[AnyRef] = null
+ val collection: Iterable[AnyRef] = nullJCollection
+
+ assert(collection == null)
+ }
+
+ @Test def testBufferWrapping(): Unit = {
+ val nullJList: ju.List[AnyRef] = null
+ val buffer: mutable.Buffer[AnyRef] = nullJList
+
+ assert(buffer == null)
+ }
+
+ @Test def testSetWrapping(): Unit = {
+ val nullJSet: ju.Set[AnyRef] = null
+ val set: mutable.Set[AnyRef] = nullJSet
+
+ assert(set == null)
+ }
+
+ @Test def testMapWrapping(): Unit = {
+ val nullJMap: ju.Map[AnyRef, AnyRef] = null
+ val map: mutable.Map[AnyRef, AnyRef] = nullJMap
+
+ assert(map == null)
+ }
+
+ @Test def testConcurrentMapWrapping(): Unit = {
+ val nullJConMap: juc.ConcurrentMap[AnyRef, AnyRef] = null
+ val conMap: concurrent.Map[AnyRef, AnyRef] = nullJConMap
+
+ assert(conMap == null)
+ }
+
+ @Test def testDictionaryWrapping(): Unit = {
+ val nullJDict: ju.Dictionary[AnyRef, AnyRef] = null
+ val dict: mutable.Map[AnyRef, AnyRef] = nullJDict
+
+ assert(dict == null)
+ }
+
+
+ @Test def testPropertyWrapping(): Unit = {
+ val nullJProps: ju.Properties = null
+ val props: mutable.Map[String, String] = nullJProps
+
+ assert(props == null)
+ }
+
+ @Test def testIteratorDecoration(): Unit = {
+ val nullJIterator: ju.Iterator[AnyRef] = null
+
+ assert(nullJIterator.asScala == null)
+ }
+
+ @Test def testEnumerationDecoration(): Unit = {
+ val nullJEnumeration: ju.Enumeration[AnyRef] = null
+
+ assert(nullJEnumeration.asScala == null)
+ }
+
+ @Test def testIterableDecoration(): Unit = {
+ val nullJIterable: jl.Iterable[AnyRef] = null
+
+ assert(nullJIterable.asScala == null)
+ }
+
+ @Test def testCollectionDecoration(): Unit = {
+ val nullJCollection: ju.Collection[AnyRef] = null
+
+ assert(nullJCollection.asScala == null)
+ }
+
+ @Test def testBufferDecoration(): Unit = {
+ val nullJBuffer: ju.List[AnyRef] = null
+
+ assert(nullJBuffer.asScala == null)
+ }
+
+ @Test def testSetDecoration(): Unit = {
+ val nullJSet: ju.Set[AnyRef] = null
+
+ assert(nullJSet.asScala == null)
+ }
+
+ @Test def testMapDecoration(): Unit = {
+ val nullJMap: ju.Map[AnyRef, AnyRef] = null
+
+ assert(nullJMap.asScala == null)
+ }
+
+ @Test def testConcurrentMapDecoration(): Unit = {
+ val nullJConMap: juc.ConcurrentMap[AnyRef, AnyRef] = null
+
+ assert(nullJConMap.asScala == null)
+ }
+
+ @Test def testDictionaryDecoration(): Unit = {
+ val nullJDict: ju.Dictionary[AnyRef, AnyRef] = null
+
+ assert(nullJDict.asScala == null)
+ }
+
+ @Test def testPropertiesDecoration(): Unit = {
+ val nullJProperties: ju.Properties = null
+
+ assert(nullJProperties.asScala == null)
+ }
+}
diff --git a/test/junit/scala/collection/immutable/ListMapTest.scala b/test/junit/scala/collection/immutable/ListMapTest.scala
new file mode 100644
index 0000000000..320a976755
--- /dev/null
+++ b/test/junit/scala/collection/immutable/ListMapTest.scala
@@ -0,0 +1,48 @@
+package scala.collection.immutable
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(classOf[JUnit4])
+class ListMapTest {
+
+ @Test
+ def t7445(): Unit = {
+ val m = ListMap(1 -> 1, 2 -> 2, 3 -> 3, 4 -> 4, 5 -> 5)
+ assertEquals(ListMap(2 -> 2, 3 -> 3, 4 -> 4, 5 -> 5), m.tail)
+ }
+
+ @Test
+ def hasCorrectBuilder(): Unit = {
+ val m = ListMap("a" -> "1", "b" -> "2", "c" -> "3", "b" -> "2.2", "d" -> "4")
+ assertEquals(List("a" -> "1", "c" -> "3", "b" -> "2.2", "d" -> "4"), m.toList)
+ }
+
+ @Test
+ def hasCorrectHeadTailLastInit(): Unit = {
+ val m = ListMap(1 -> 1, 2 -> 2, 3 -> 3)
+ assertEquals(1 -> 1, m.head)
+ assertEquals(ListMap(2 -> 2, 3 -> 3), m.tail)
+ assertEquals(3 -> 3, m.last)
+ assertEquals(ListMap(1 -> 1, 2 -> 2), m.init)
+ }
+
+ @Test
+ def hasCorrectAddRemove(): Unit = {
+ val m = ListMap(1 -> 1, 2 -> 2, 3 -> 3)
+ assertEquals(ListMap(1 -> 1, 2 -> 2, 3 -> 3, 4 -> 4), m + (4 -> 4))
+ assertEquals(ListMap(1 -> 1, 3 -> 3, 2 -> 4), m + (2 -> 4))
+ assertEquals(ListMap(1 -> 1, 2 -> 2, 3 -> 3), m + (2 -> 2))
+ assertEquals(ListMap(2 -> 2, 3 -> 3), m - 1)
+ assertEquals(ListMap(1 -> 1, 3 -> 3), m - 2)
+ assertEquals(ListMap(1 -> 1, 2 -> 2, 3 -> 3), m - 4)
+ }
+
+ @Test
+ def hasCorrectIterator(): Unit = {
+ val m = ListMap(1 -> 1, 2 -> 2, 3 -> 3, 5 -> 5, 4 -> 4)
+ assertEquals(List(1 -> 1, 2 -> 2, 3 -> 3, 5 -> 5, 4 -> 4), m.iterator.toList)
+ }
+}
diff --git a/test/junit/scala/collection/immutable/ListSetTest.scala b/test/junit/scala/collection/immutable/ListSetTest.scala
new file mode 100644
index 0000000000..395da88c75
--- /dev/null
+++ b/test/junit/scala/collection/immutable/ListSetTest.scala
@@ -0,0 +1,53 @@
+package scala.collection.immutable
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(classOf[JUnit4])
+class ListSetTest {
+
+ @Test
+ def t7445(): Unit = {
+ val s = ListSet(1, 2, 3, 4, 5)
+ assertEquals(ListSet(2, 3, 4, 5), s.tail)
+ }
+
+ @Test
+ def hasCorrectBuilder(): Unit = {
+ val m = ListSet("a", "b", "c", "b", "d")
+ assertEquals(List("a", "b", "c", "d"), m.toList)
+ }
+
+ @Test
+ def hasTailRecursiveDelete(): Unit = {
+ val s = ListSet(1 to 50000: _*)
+ try s - 25000 catch { case e: StackOverflowError => fail("A stack overflow occurred") }
+ }
+
+ @Test
+ def hasCorrectHeadTailLastInit(): Unit = {
+ val m = ListSet(1, 2, 3)
+ assertEquals(1, m.head)
+ assertEquals(ListSet(2, 3), m.tail)
+ assertEquals(3, m.last)
+ assertEquals(ListSet(1, 2), m.init)
+ }
+
+ @Test
+ def hasCorrectAddRemove(): Unit = {
+ val m = ListSet(1, 2, 3)
+ assertEquals(ListSet(1, 2, 3, 4), m + 4)
+ assertEquals(ListSet(1, 2, 3), m + 2)
+ assertEquals(ListSet(2, 3), m - 1)
+ assertEquals(ListSet(1, 3), m - 2)
+ assertEquals(ListSet(1, 2, 3), m - 4)
+ }
+
+ @Test
+ def hasCorrectIterator(): Unit = {
+ val s = ListSet(1, 2, 3, 5, 4)
+ assertEquals(List(1, 2, 3, 5, 4), s.iterator.toList)
+ }
+}
diff --git a/test/junit/scala/issues/BytecodeTest.scala b/test/junit/scala/issues/BytecodeTest.scala
deleted file mode 100644
index cf5c7f9ec3..0000000000
--- a/test/junit/scala/issues/BytecodeTest.scala
+++ /dev/null
@@ -1,478 +0,0 @@
-package scala.issues
-
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-import org.junit.Test
-
-import scala.tools.asm.Opcodes._
-import scala.tools.nsc.backend.jvm.AsmUtils
-import scala.tools.nsc.backend.jvm.CodeGenTools._
-import org.junit.Assert._
-
-import scala.collection.JavaConverters._
-import scala.tools.asm.Opcodes
-import scala.tools.asm.tree.ClassNode
-import scala.tools.partest.ASMConverters._
-import scala.tools.testing.ClearAfterClass
-
-object BytecodeTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler()
- def clear(): Unit = { compiler = null }
-}
-
-@RunWith(classOf[JUnit4])
-class BytecodeTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = BytecodeTest
- val compiler = BytecodeTest.compiler
-
- @Test
- def t8731(): Unit = {
- val code =
- """class C {
- | def f(x: Int) = (x: @annotation.switch) match {
- | case 1 => 0
- | case 2 => 1
- | case 3 => 2
- | }
- | final val K = 10
- | def g(x: Int) = (x: @annotation.switch) match {
- | case K => 0
- | case 1 => 10
- | case 2 => 20
- | }
- |}
- """.stripMargin
-
- val List(c) = compileClasses(compiler)(code)
-
- assertTrue(getSingleMethod(c, "f").instructions.count(_.isInstanceOf[TableSwitch]) == 1)
- assertTrue(getSingleMethod(c, "g").instructions.count(_.isInstanceOf[LookupSwitch]) == 1)
- }
-
- @Test
- def t8926(): Unit = {
- import scala.reflect.internal.util.BatchSourceFile
-
- // this test cannot be implemented using partest because of its mixed-mode compilation strategy:
- // partest first compiles all files with scalac, then the java files, and then again the scala
- // using the output classpath. this shadows the bug SI-8926.
-
- val annotA =
- """import java.lang.annotation.Retention;
- |import java.lang.annotation.RetentionPolicy;
- |@Retention(RetentionPolicy.RUNTIME)
- |public @interface AnnotA { }
- """.stripMargin
- val annotB = "public @interface AnnotB { }"
-
- val scalaSrc =
- """@AnnotA class A
- |@AnnotB class B
- """.stripMargin
-
- val run = new compiler.Run()
- run.compileSources(List(new BatchSourceFile("AnnotA.java", annotA), new BatchSourceFile("AnnotB.java", annotB), new BatchSourceFile("Test.scala", scalaSrc)))
- val outDir = compiler.settings.outputDirs.getSingleOutput.get
- val outfiles = (for (f <- outDir.iterator if !f.isDirectory) yield (f.name, f.toByteArray)).toList
-
- def check(classfile: String, annotName: String) = {
- val f = (outfiles collect { case (`classfile`, bytes) => AsmUtils.readClass(bytes) }).head
- val descs = f.visibleAnnotations.asScala.map(_.desc).toList
- assertTrue(descs.toString, descs exists (_ contains annotName))
- }
-
- check("A.class", "AnnotA")
-
- // known issue SI-8928: the visibility of AnnotB should be CLASS, but annotation classes without
- // a @Retention annotation are currently emitted as RUNTIME.
- check("B.class", "AnnotB")
- }
-
- @Test
- def t6288bJumpPosition(): Unit = {
- val code =
- """object Case3 { // 01
- | def unapply(z: Any): Option[Int] = Some(-1) // 02
- | def main(args: Array[String]) { // 03
- | ("": Any) match { // 04
- | case x : String => // 05
- | println("case 0") // 06 println and jump at 6
- | case _ => // 07
- | println("default") // 08 println and jump at 8
- | } // 09
- | println("done") // 10
- | }
- |}
- """.stripMargin
- val List(mirror, module) = compileClasses(compiler)(code)
-
- val unapplyLineNumbers = getSingleMethod(module, "unapply").instructions.filter(_.isInstanceOf[LineNumber])
- assert(unapplyLineNumbers == List(LineNumber(2, Label(0))), unapplyLineNumbers)
-
- val expected = List(
- LineNumber(4, Label(0)),
- LineNumber(5, Label(5)),
- Jump(IFEQ, Label(20)),
-
- LineNumber(6, Label(11)),
- Invoke(INVOKEVIRTUAL, "scala/Predef$", "println", "(Ljava/lang/Object;)V", false),
- Jump(GOTO, Label(33)),
-
- LineNumber(5, Label(20)),
- Jump(GOTO, Label(24)),
-
- LineNumber(8, Label(24)),
- Invoke(INVOKEVIRTUAL, "scala/Predef$", "println", "(Ljava/lang/Object;)V", false),
- Jump(GOTO, Label(33)),
-
- LineNumber(10, Label(33)),
- Invoke(INVOKEVIRTUAL, "scala/Predef$", "println", "(Ljava/lang/Object;)V", false)
- )
-
- val mainIns = getSingleMethod(module, "main").instructions filter {
- case _: LineNumber | _: Invoke | _: Jump => true
- case _ => false
- }
- assertSameCode(mainIns, expected)
- }
-
- @Test
- def bytecodeForBranches(): Unit = {
- val code =
- """class C {
- | def t1(b: Boolean) = if (b) 1 else 2
- | def t2(x: Int) = if (x == 393) 1 else 2
- | def t3(a: Array[String], b: AnyRef) = a != b && b == a
- | def t4(a: AnyRef) = a == null || null != a
- | def t5(a: AnyRef) = (a eq null) || (null ne a)
- | def t6(a: Int, b: Boolean) = if ((a == 10) && b || a != 1) 1 else 2
- | def t7(a: AnyRef, b: AnyRef) = a == b
- | def t8(a: AnyRef) = Nil == a || "" != a
- |}
- """.stripMargin
-
- val List(c) = compileClasses(compiler)(code)
-
- // t1: no unnecessary GOTOs
- assertSameCode(getSingleMethod(c, "t1"), List(
- VarOp(ILOAD, 1), Jump(IFEQ, Label(6)),
- Op(ICONST_1), Jump(GOTO, Label(9)),
- Label(6), Op(ICONST_2),
- Label(9), Op(IRETURN)))
-
- // t2: no unnecessary GOTOs
- assertSameCode(getSingleMethod(c, "t2"), List(
- VarOp(ILOAD, 1), IntOp(SIPUSH, 393), Jump(IF_ICMPNE, Label(7)),
- Op(ICONST_1), Jump(GOTO, Label(10)),
- Label(7), Op(ICONST_2),
- Label(10), Op(IRETURN)))
-
- // t3: Array == is translated to reference equality, AnyRef == to null checks and equals
- assertSameCode(getSingleMethod(c, "t3"), List(
- // Array ==
- VarOp(ALOAD, 1), VarOp(ALOAD, 2), Jump(IF_ACMPEQ, Label(23)),
- // AnyRef ==
- VarOp(ALOAD, 2), VarOp(ALOAD, 1), VarOp(ASTORE, 3), Op(DUP), Jump(IFNONNULL, Label(14)),
- Op(POP), VarOp(ALOAD, 3), Jump(IFNULL, Label(19)), Jump(GOTO, Label(23)),
- Label(14), VarOp(ALOAD, 3), Invoke(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false), Jump(IFEQ, Label(23)),
- Label(19), Op(ICONST_1), Jump(GOTO, Label(26)),
- Label(23), Op(ICONST_0),
- Label(26), Op(IRETURN)))
-
- val t4t5 = List(
- VarOp(ALOAD, 1), Jump(IFNULL, Label(6)),
- VarOp(ALOAD, 1), Jump(IFNULL, Label(10)),
- Label(6), Op(ICONST_1), Jump(GOTO, Label(13)),
- Label(10), Op(ICONST_0),
- Label(13), Op(IRETURN))
-
- // t4: one side is known null, so just a null check on the other
- assertSameCode(getSingleMethod(c, "t4"), t4t5)
-
- // t5: one side known null, so just a null check on the other
- assertSameCode(getSingleMethod(c, "t5"), t4t5)
-
- // t6: no unnecessary GOTOs
- assertSameCode(getSingleMethod(c, "t6"), List(
- VarOp(ILOAD, 1), IntOp(BIPUSH, 10), Jump(IF_ICMPNE, Label(7)),
- VarOp(ILOAD, 2), Jump(IFNE, Label(12)),
- Label(7), VarOp(ILOAD, 1), Op(ICONST_1), Jump(IF_ICMPEQ, Label(16)),
- Label(12), Op(ICONST_1), Jump(GOTO, Label(19)),
- Label(16), Op(ICONST_2),
- Label(19), Op(IRETURN)))
-
- // t7: universal equality
- assertInvoke(getSingleMethod(c, "t7"), "scala/runtime/BoxesRunTime", "equals")
-
- // t8: no null checks invoking equals on modules and constants
- assertSameCode(getSingleMethod(c, "t8"), List(
- Field(GETSTATIC, "scala/collection/immutable/Nil$", "MODULE$", "Lscala/collection/immutable/Nil$;"), VarOp(ALOAD, 1), Invoke(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false), Jump(IFNE, Label(10)),
- Ldc(LDC, ""), VarOp(ALOAD, 1), Invoke(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false), Jump(IFNE, Label(14)),
- Label(10), Op(ICONST_1), Jump(GOTO, Label(17)),
- Label(14), Op(ICONST_0),
- Label(17), Op(IRETURN)))
- }
-
- object forwarderTestUtils {
- def findMethods(cls: ClassNode, name: String): List[Method] = cls.methods.iterator.asScala.find(_.name == name).map(convertMethod).toList
-
- import language.implicitConversions
- implicit def s2c(s: Symbol)(implicit classes: Map[String, ClassNode]): ClassNode = classes(s.name)
-
- def checkForwarder(c: ClassNode, target: String) = {
- val List(f) = findMethods(c, "f")
- assertSameCode(f, List(VarOp(ALOAD, 0), Invoke(INVOKESPECIAL, target, "f", "()I", false), Op(IRETURN)))
- }
- }
-
- @Test
- def traitMethodForwarders(): Unit = {
- import forwarderTestUtils._
- val code =
- """trait T1 { def f = 1 }
- |trait T2 extends T1 { override def f = 2 }
- |trait T3 { self: T1 => override def f = 3 }
- |
- |abstract class A1 { def f: Int }
- |class A2 { def f: Int = 4 }
- |
- |trait T4 extends A1 { def f = 5 }
- |trait T5 extends A2 { override def f = 6 }
- |
- |trait T6 { def f: Int }
- |trait T7 extends T6 { abstract override def f = super.f + 1 }
- |
- |trait T8 { override def clone() = super.clone() }
- |
- |class A3 extends T1 { override def f = 7 }
- |
- |class C1 extends T1
- |class C2 extends T2
- |class C3 extends T1 with T2
- |class C4 extends T2 with T1
- |class C5 extends T1 with T3
- |
- |// traits extending a class that defines f
- |class C6 extends T4
- |class C7 extends T5
- |class C8 extends A1 with T4
- |class C9 extends A2 with T5
- |
- |// T6: abstract f in trait
- |class C10 extends T6 with T1
- |class C11 extends T6 with T2
- |abstract class C12 extends A1 with T6
- |class C13 extends A2 with T6
- |class C14 extends T4 with T6
- |class C15 extends T5 with T6
- |
- |// superclass overrides a trait method
- |class C16 extends A3
- |class C17 extends A3 with T1
- |
- |// abstract override
- |class C18 extends T6 { def f = 22 }
- |class C19 extends C18 with T7
- |
- |class C20 extends T8
- """.stripMargin
-
- implicit val classes = compileClasses(compiler)(code).map(c => (c.name, c)).toMap
-
- val noForwarder = List('C1, 'C2, 'C3, 'C4, 'C10, 'C11, 'C12, 'C13, 'C16, 'C17)
- for (c <- noForwarder) assertEquals(findMethods(c, "f"), Nil)
-
- checkForwarder('C5, "T3")
- checkForwarder('C6, "T4")
- checkForwarder('C7, "T5")
- checkForwarder('C8, "T4")
- checkForwarder('C9, "T5")
- checkForwarder('C14, "T4")
- checkForwarder('C15, "T5")
- assertSameSummary(getSingleMethod('C18, "f"), List(BIPUSH, IRETURN))
- checkForwarder('C19, "T7")
- assertSameCode(getSingleMethod('C19, "T7$$super$f"), List(VarOp(ALOAD, 0), Invoke(INVOKESPECIAL, "C18", "f", "()I", false), Op(IRETURN)))
- assertInvoke(getSingleMethod('C20, "clone"), "T8", "clone") // mixin forwarder
- }
-
- @Test
- def noTraitMethodForwardersForOverloads(): Unit = {
- import forwarderTestUtils._
- val code =
- """trait T1 { def f(x: Int) = 0 }
- |trait T2 { def f(x: String) = 1 }
- |class C extends T1 with T2
- """.stripMargin
- val List(c, t1, t2) = compileClasses(compiler)(code)
- assertEquals(findMethods(c, "f"), Nil)
- }
-
- @Test
- def traitMethodForwardersForJavaDefaultMethods(): Unit = {
- import forwarderTestUtils._
- val j1 = ("interface J1 { int f(); }", "J1.java")
- val j2 = ("interface J2 { default int f() { return 1; } }", "J2.java")
- val j3 = ("interface J3 extends J1 { default int f() { return 2; } }", "J3.java")
- val j4 = ("interface J4 extends J2 { default int f() { return 3; } }", "J4.java")
- val code =
- """trait T1 extends J2 { override def f = 4 }
- |trait T2 { self: J2 => override def f = 5 }
- |
- |class K1 extends J2
- |class K2 extends J1 with J2
- |class K3 extends J2 with J1
- |
- |class K4 extends J3
- |class K5 extends J3 with J1
- |class K6 extends J1 with J3
- |
- |class K7 extends J4
- |class K8 extends J4 with J2
- |class K9 extends J2 with J4
- |
- |class K10 extends T1 with J2
- |class K11 extends J2 with T1
- |
- |class K12 extends J2 with T2
- """.stripMargin
- implicit val classes = compileClasses(compiler)(code, List(j1, j2, j3, j4)).map(c => (c.name, c)).toMap
-
- val noForwarder = List('K1, 'K2, 'K3, 'K4, 'K5, 'K6, 'K7, 'K8, 'K9, 'K10, 'K11)
- for (c <- noForwarder) assertEquals(findMethods(c, "f"), Nil)
-
- checkForwarder('K12, "T2")
- }
-
- @Test
- def invocationReceivers(): Unit = {
- val List(c1, c2, t, u) = compileClasses(compiler)(invocationReceiversTestCode.definitions("Object"))
- // mixin forwarder in C1
- assertSameCode(getSingleMethod(c1, "clone"), List(VarOp(ALOAD, 0), Invoke(INVOKESPECIAL, "T", "clone", "()Ljava/lang/Object;", false), Op(ARETURN)))
- assertInvoke(getSingleMethod(c1, "f1"), "T", "clone")
- assertInvoke(getSingleMethod(c1, "f2"), "T", "clone")
- assertInvoke(getSingleMethod(c1, "f3"), "C1", "clone")
- assertInvoke(getSingleMethod(c2, "f1"), "T", "clone")
- assertInvoke(getSingleMethod(c2, "f2"), "T", "clone")
- assertInvoke(getSingleMethod(c2, "f3"), "C1", "clone")
-
- val List(c1b, c2b, tb, ub) = compileClasses(compiler)(invocationReceiversTestCode.definitions("String"))
- def ms(c: ClassNode, n: String) = c.methods.asScala.toList.filter(_.name == n)
- assert(ms(tb, "clone").length == 1)
- assert(ms(ub, "clone").isEmpty)
- val List(c1Clone) = ms(c1b, "clone")
- assertEquals(c1Clone.desc, "()Ljava/lang/Object;")
- assert((c1Clone.access | Opcodes.ACC_BRIDGE) != 0)
- assertSameCode(convertMethod(c1Clone), List(VarOp(ALOAD, 0), Invoke(INVOKEVIRTUAL, "C1", "clone", "()Ljava/lang/String;", false), Op(ARETURN)))
-
- def iv(m: Method) = getSingleMethod(c1b, "f1").instructions.collect({case i: Invoke => i})
- assertSameCode(iv(getSingleMethod(c1b, "f1")), List(Invoke(INVOKEINTERFACE, "T", "clone", "()Ljava/lang/String;", true)))
- assertSameCode(iv(getSingleMethod(c1b, "f2")), List(Invoke(INVOKEINTERFACE, "T", "clone", "()Ljava/lang/String;", true)))
- // invokeinterface T.clone in C1 is OK here because it is not an override of Object.clone (different siganture)
- assertSameCode(iv(getSingleMethod(c1b, "f3")), List(Invoke(INVOKEINTERFACE, "T", "clone", "()Ljava/lang/String;", true)))
- }
-
- @Test
- def invocationReceiversProtected(): Unit = {
- // http://lrytz.github.io/scala-aladdin-bugtracker/displayItem.do%3Fid=455.html / 9954eaf
- // also https://issues.scala-lang.org/browse/SI-1430 / 0bea2ab (same but with interfaces)
- val aC =
- """package a;
- |/*package private*/ abstract class A {
- | public int f() { return 1; }
- | public int t;
- |}
- """.stripMargin
- val bC =
- """package a;
- |public class B extends A { }
- """.stripMargin
- val iC =
- """package a;
- |/*package private*/ interface I { int f(); }
- """.stripMargin
- val jC =
- """package a;
- |public interface J extends I { }
- """.stripMargin
- val cC =
- """package b
- |class C {
- | def f1(b: a.B) = b.f
- | def f2(b: a.B) = { b.t = b.t + 1 }
- | def f3(j: a.J) = j.f
- |}
- """.stripMargin
- val List(c) = compileClasses(compiler)(cC, javaCode = List((aC, "A.java"), (bC, "B.java"), (iC, "I.java"), (jC, "J.java")))
- assertInvoke(getSingleMethod(c, "f1"), "a/B", "f") // receiver needs to be B (A is not accessible in class C, package b)
- println(getSingleMethod(c, "f2").instructions.stringLines)
- assertInvoke(getSingleMethod(c, "f3"), "a/J", "f") // receiver needs to be J
- }
-
- @Test
- def specialInvocationReceivers(): Unit = {
- val code =
- """class C {
- | def f1(a: Array[String]) = a.clone()
- | def f2(a: Array[Int]) = a.hashCode()
- | def f3(n: Nothing) = n.hashCode()
- | def f4(n: Null) = n.toString()
- |
- |}
- """.stripMargin
- val List(c) = compileClasses(compiler)(code)
- assertInvoke(getSingleMethod(c, "f1"), "[Ljava/lang/String;", "clone") // array descriptor as receiver
- assertInvoke(getSingleMethod(c, "f2"), "java/lang/Object", "hashCode") // object receiver
- assertInvoke(getSingleMethod(c, "f3"), "java/lang/Object", "hashCode")
- assertInvoke(getSingleMethod(c, "f4"), "java/lang/Object", "toString")
- }
-}
-
-object invocationReceiversTestCode {
- // if cloneType is more specific than Object (e.g., String), a bridge method is generated.
- def definitions(cloneType: String) =
- s"""trait T { override def clone(): $cloneType = "hi" }
- |trait U extends T
- |class C1 extends U with Cloneable {
- | // The comments below are true when $cloneType is Object.
- | // C1 gets a forwarder for clone that invokes T.clone. this is needed because JVM method
- | // resolution always prefers class members, so it would resolve to Object.clone, even if
- | // C1 is a subtype of the interface T which has an overriding default method for clone.
- |
- | // invokeinterface T.clone
- | def f1 = (this: T).clone()
- |
- | // cannot invokeinterface U.clone (NoSuchMethodError). Object.clone would work here, but
- | // not in the example in C2 (illegal access to protected). T.clone works in all cases and
- | // resolves correctly.
- | def f2 = (this: U).clone()
- |
- | // invokevirtual C1.clone()
- | def f3 = (this: C1).clone()
- |}
- |
- |class C2 {
- | def f1(t: T) = t.clone() // invokeinterface T.clone
- | def f2(t: U) = t.clone() // invokeinterface T.clone -- Object.clone would be illegal (protected, explained in C1)
- | def f3(t: C1) = t.clone() // invokevirtual C1.clone -- Object.clone would be illegal
- |}
- """.stripMargin
-
- val runCode =
- """
- |val r = new StringBuffer()
- |val c1 = new C1
- |r.append(c1.f1)
- |r.append(c1.f2)
- |r.append(c1.f3)
- |val t = new T { }
- |val u = new U { }
- |val c2 = new C2
- |r.append(c2.f1(t))
- |r.append(c2.f1(u))
- |r.append(c2.f1(c1))
- |r.append(c2.f2(u))
- |r.append(c2.f2(c1))
- |r.append(c2.f3(c1))
- |r.toString
- """.stripMargin
-}
diff --git a/test/junit/scala/lang/annotations/BytecodeTest.scala b/test/junit/scala/lang/annotations/BytecodeTest.scala
new file mode 100644
index 0000000000..09fc1d3572
--- /dev/null
+++ b/test/junit/scala/lang/annotations/BytecodeTest.scala
@@ -0,0 +1,80 @@
+package scala.lang.annotations
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+import scala.collection.JavaConverters._
+import scala.tools.nsc.backend.jvm.AsmUtils
+import scala.tools.partest.ASMConverters._
+import scala.tools.testing.BytecodeTesting
+import scala.tools.testing.BytecodeTesting._
+
+@RunWith(classOf[JUnit4])
+class BytecodeTest extends BytecodeTesting {
+ import compiler._
+
+ @Test
+ def t8731(): Unit = {
+ val code =
+ """class C {
+ | def f(x: Int) = (x: @annotation.switch) match {
+ | case 1 => 0
+ | case 2 => 1
+ | case 3 => 2
+ | }
+ | final val K = 10
+ | def g(x: Int) = (x: @annotation.switch) match {
+ | case K => 0
+ | case 1 => 10
+ | case 2 => 20
+ | }
+ |}
+ """.stripMargin
+
+ val c = compileClass(code)
+
+ assertTrue(getInstructions(c, "f").count(_.isInstanceOf[TableSwitch]) == 1)
+ assertTrue(getInstructions(c, "g").count(_.isInstanceOf[LookupSwitch]) == 1)
+ }
+
+ @Test
+ def t8926(): Unit = {
+ import scala.reflect.internal.util.BatchSourceFile
+
+ // this test cannot be implemented using partest because of its mixed-mode compilation strategy:
+ // partest first compiles all files with scalac, then the java files, and then again the scala
+ // using the output classpath. this shadows the bug SI-8926.
+
+ val annotA =
+ """import java.lang.annotation.Retention;
+ |import java.lang.annotation.RetentionPolicy;
+ |@Retention(RetentionPolicy.RUNTIME)
+ |public @interface AnnotA { }
+ """.stripMargin
+ val annotB = "public @interface AnnotB { }"
+
+ val scalaSrc =
+ """@AnnotA class A
+ |@AnnotB class B
+ """.stripMargin
+
+ val run = new global.Run()
+ run.compileSources(List(new BatchSourceFile("AnnotA.java", annotA), new BatchSourceFile("AnnotB.java", annotB), new BatchSourceFile("Test.scala", scalaSrc)))
+ val outDir = global.settings.outputDirs.getSingleOutput.get
+ val outfiles = (for (f <- outDir.iterator if !f.isDirectory) yield (f.name, f.toByteArray)).toList
+
+ def check(classfile: String, annotName: String) = {
+ val f = (outfiles collect { case (`classfile`, bytes) => AsmUtils.readClass(bytes) }).head
+ val descs = f.visibleAnnotations.asScala.map(_.desc).toList
+ assertTrue(descs.toString, descs exists (_ contains annotName))
+ }
+
+ check("A.class", "AnnotA")
+
+ // known issue SI-8928: the visibility of AnnotB should be CLASS, but annotation classes without
+ // a @Retention annotation are currently emitted as RUNTIME.
+ check("B.class", "AnnotB")
+ }
+} \ No newline at end of file
diff --git a/test/junit/scala/lang/annotations/RunTest.scala b/test/junit/scala/lang/annotations/RunTest.scala
new file mode 100644
index 0000000000..0d9c0c4713
--- /dev/null
+++ b/test/junit/scala/lang/annotations/RunTest.scala
@@ -0,0 +1,32 @@
+package scala.lang.annotations
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+import scala.tools.testing.RunTesting
+
+@RunWith(classOf[JUnit4])
+class RunTest extends RunTesting {
+ import runner._
+
+ @Test
+ def annotationInfoNotErased(): Unit = {
+ val code =
+ """import javax.annotation.Resource
+ |import scala.annotation.meta.getter
+ |class C {
+ | type Rg = Resource @getter
+ | @(Resource @getter)(`type` = classOf[Int]) def a = 0
+ | @Rg(`type` = classOf[Int]) def b = 0
+ |}
+ |val c = classOf[C]
+ |def typeArg(meth: String) = c.getDeclaredMethod(meth).getDeclaredAnnotation(classOf[Resource]).`type`
+ |List("a", "b") map typeArg
+ |""".stripMargin
+
+ val i = Integer.TYPE
+ assertEquals(run[List[Class[_]]](code), List(i, i))
+ }
+}
diff --git a/test/junit/scala/lang/primitives/BoxUnboxTest.scala b/test/junit/scala/lang/primitives/BoxUnboxTest.scala
new file mode 100644
index 0000000000..e4911f1af5
--- /dev/null
+++ b/test/junit/scala/lang/primitives/BoxUnboxTest.scala
@@ -0,0 +1,249 @@
+package scala.lang.primitives
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+import scala.tools.testing.RunTesting
+
+object BoxUnboxTest {
+ class VCI(val x: Int) extends AnyVal { override def toString = "" + x }
+}
+
+@RunWith(classOf[JUnit4])
+class BoxUnboxTest extends RunTesting {
+ import runner._
+
+ @Test
+ def boxUnboxInt(): Unit = {
+ // Once we use 2.12.0-M5 as starr, this code can be run directly in the JUnit test.
+ // Some fixes not yet available in M4 make the test fail when compiled with M4.
+ val code =
+ """import scala.tools.testing.AssertUtil._
+ |import org.junit.Assert._
+ |
+ |def genericNull[T] = null.asInstanceOf[T] // allowed, see SI-4437, point 2
+ |
+ |val b = new Integer(1)
+ |val u = 1
+ |
+ |assertEquals(1.toInt, u)
+ |
+ |assertEquals(Predef.int2Integer(1), b)
+ |assertEquals(1: Integer, b)
+ |assertEquals(Int.box(1), b)
+ |assertEquals(1.asInstanceOf[Object], b)
+ |
+ |assertThrows[ClassCastException]("".asInstanceOf[Integer])
+ |
+ |assertEquals(Predef.Integer2int(b), u)
+ |assertEquals(b: Int, u)
+ |assertEquals(Int.unbox(b), u)
+ |assertEquals(b.asInstanceOf[Int], u)
+ |assertEquals(b.intValue, u)
+ |assertEquals(b.toInt, u)
+ |intWrapper(b).toInt
+ |
+ |assertThrows[ClassCastException](Int.unbox(""))
+ |assertThrows[ClassCastException]("".asInstanceOf[Int])
+ |
+ |// null unboxing in various positions
+ |
+ |val n1 = Int.unbox(null)
+ |assertEquals(n1, 0)
+ |val n2 = Predef.Integer2int(null)
+ |assertEquals(n2, 0)
+ |val n3 = (null: Integer): Int
+ |assertEquals(n3, 0)
+ |val n4 = null.asInstanceOf[Int]
+ |assertEquals(n4, 0)
+ |val n5 = null.asInstanceOf[Int] == 0
+ |assertTrue(n5)
+ |val n6 = null.asInstanceOf[Int] == null
+ |assertFalse(n6)
+ |val n7 = null.asInstanceOf[Int] != 0
+ |assertFalse(n7)
+ |val n8 = null.asInstanceOf[Int] != null
+ |assertTrue(n8)
+ |
+ |val mp = new java.util.HashMap[Int, Int]
+ |val n9 = mp.get(0)
+ |assertEquals(n9, 0)
+ |val n10 = mp.get(0) == null // SI-602
+ |assertThrows[AssertionError](assertFalse(n10)) // should not throw
+ |
+ |def f(a: Any) = "" + a
+ |val n11 = f(null.asInstanceOf[Int])
+ |assertEquals(n11, "0")
+ |
+ |def n12 = genericNull[Int]
+ |assertEquals(n12, 0)
+ """.stripMargin
+
+ run[Unit](code)
+ }
+
+ @Test
+ def numericConversions(): Unit = {
+ // Once we use 2.12.0-M5 as starr, this code can be run directly in the JUnit test.
+ val code =
+ """import scala.tools.testing.AssertUtil._
+ |import org.junit.Assert._
+ |
+ |val i1 = 1L.asInstanceOf[Int]
+ |assertEquals(i1, 1)
+ |assertThrows[ClassCastException] {
+ | val i2 = (1L: Any).asInstanceOf[Int] // SI-1448, should not throw. see also SI-4437 point 1.
+ | assertEquals(i2, 1)
+ |}
+ """.stripMargin
+ run[Unit](code)
+ }
+
+ @Test
+ def boxUnboxBoolean(): Unit = {
+ // Once we use 2.12.0-M5 as starr, this code can be run directly in the JUnit test.
+ val code =
+ """val n1 = Option(null.asInstanceOf[Boolean])
+ |n1
+ """.stripMargin
+ assertEquals(run[Option[Boolean]](code), Some(false))
+ }
+
+ @Test
+ def boxUnboxUnit(): Unit = {
+ // should not use assertEquals in this test: it takes two Object parameters. normally, Unit does
+ // not conform to Object, but for Java-defined methods scalac makes an exception and treats them
+ // as Any. passing a Unit as Any makes the compiler go through another layer of boxing, so it
+ // can hide some bugs (where we actually have a null, but the compiler makes it a ()).
+
+ // Once we use 2.12.0-M5 as starr, this code can be run directly in the JUnit test.
+ val code =
+ """import scala.tools.testing.AssertUtil._
+ |import org.junit.Assert._
+ |
+ |var v = 0
+ |def eff() = { v = 1 }
+ |def chk() = { assert(v == 1); v = 0 }
+ |
+ |val b = runtime.BoxedUnit.UNIT
+ |
+ |assert(eff() == b); chk()
+ |assert(Unit.box(eff()) == b); chk()
+ |assert(().asInstanceOf[Object] == b)
+ |
+ |Unit.unbox({eff(); b}); chk()
+ |Unit.unbox({eff(); null}); chk()
+ |assertThrows[ClassCastException](Unit.unbox({eff(); ""})); chk()
+ |
+ |val n1 = null.asInstanceOf[Unit]
+ |assert(n1 == b)
+ |
+ |val n2 = null.asInstanceOf[Unit] == b
+ |assert(n2)
+ |
+ |def f(a: Any) = "" + a
+ |val n3 = f(null.asInstanceOf[Unit])
+ |assertEquals(n3, "()")
+ """.stripMargin
+ run[Unit](code)
+ }
+
+ @Test
+ def t9671(): Unit = {
+ // Once we use 2.12.0-M5 as starr, this code can be run directly in the JUnit test.
+ val code =
+ """import scala.lang.primitives.BoxUnboxTest.VCI
+ |
+ |def f1(a: Any) = "" + a
+ |def f2(a: AnyVal) = "" + a
+ |def f3[T](a: T) = "" + a
+ |def f4(a: Int) = "" + a
+ |def f5(a: VCI) = "" + a
+ |def f6(u: Unit) = "" + u
+ |
+ |def n1: AnyRef = null
+ |def n2: Null = null
+ |def n3: Any = null
+ |def n4[T]: T = null.asInstanceOf[T]
+ |
+ |def npe(s: => String) = try { s; throw new Error() } catch { case _: NullPointerException => "npe" }
+ |
+ | f1(null.asInstanceOf[Int]) +
+ | f1( n1.asInstanceOf[Int]) +
+ | f1( n2.asInstanceOf[Int]) +
+ | f1( n3.asInstanceOf[Int]) +
+ | f1( n4[Int]) + // "null"
+ |"-" +
+ | f1(null.asInstanceOf[VCI]) +
+ |npe(f1( n1.asInstanceOf[VCI])) + // SI-8097
+ | f1( n2.asInstanceOf[VCI]) +
+ |npe(f1( n3.asInstanceOf[VCI])) + // SI-8097
+ | f1( n4[VCI]) + // "null"
+ |"-" +
+ | f1(null.asInstanceOf[Unit]) +
+ | f1( n1.asInstanceOf[Unit]) +
+ | f1( n2.asInstanceOf[Unit]) +
+ | f1( n3.asInstanceOf[Unit]) +
+ | f1( n4[Unit]) + // "null"
+ |"-" +
+ | f2(null.asInstanceOf[Int]) +
+ | f2( n1.asInstanceOf[Int]) +
+ | f2( n2.asInstanceOf[Int]) +
+ | f2( n3.asInstanceOf[Int]) +
+ | f2( n4[Int]) + // "null"
+ |"-" +
+ | f2(null.asInstanceOf[VCI]) +
+ |npe(f2( n1.asInstanceOf[VCI])) + // SI-8097
+ | f2( n2.asInstanceOf[VCI]) +
+ |npe(f2( n3.asInstanceOf[VCI])) + // SI-8097
+ | f2( n4[VCI]) + // "null"
+ |"-" +
+ | f2(null.asInstanceOf[Unit]) +
+ | f2( n1.asInstanceOf[Unit]) +
+ | f2( n2.asInstanceOf[Unit]) +
+ | f2( n3.asInstanceOf[Unit]) +
+ | f2( n4[Unit]) + // "null"
+ |"-" +
+ | f3(null.asInstanceOf[Int]) +
+ | f3( n1.asInstanceOf[Int]) +
+ | f3( n2.asInstanceOf[Int]) +
+ | f3( n3.asInstanceOf[Int]) +
+ | f3( n4[Int]) + // "null"
+ |"-" +
+ | f3(null.asInstanceOf[VCI]) +
+ |npe(f3( n1.asInstanceOf[VCI])) + // SI-8097
+ | f3( n2.asInstanceOf[VCI]) +
+ |npe(f3( n3.asInstanceOf[VCI])) + // SI-8097
+ | f3( n4[VCI]) + // "null"
+ |"-" +
+ | f3(null.asInstanceOf[Unit]) +
+ | f3( n1.asInstanceOf[Unit]) +
+ | f3( n2.asInstanceOf[Unit]) +
+ | f3( n3.asInstanceOf[Unit]) +
+ | f3( n4[Unit]) + // "null"
+ |"-" +
+ | f4(null.asInstanceOf[Int]) +
+ | f4( n1.asInstanceOf[Int]) +
+ | f4( n2.asInstanceOf[Int]) +
+ | f4( n3.asInstanceOf[Int]) +
+ | f4( n4[Int]) +
+ |"-" +
+ | f5(null.asInstanceOf[VCI]) +
+ |npe(f5( n1.asInstanceOf[VCI])) + // SI-8097
+ | f5( n2.asInstanceOf[VCI]) +
+ |npe(f5( n3.asInstanceOf[VCI])) + // SI-8097
+ |npe(f5( n4[VCI])) + // SI-8097
+ |"-" +
+ | f6(null.asInstanceOf[Unit]) +
+ | f6( n1.asInstanceOf[Unit]) +
+ | f6( n2.asInstanceOf[Unit]) +
+ | f6( n3.asInstanceOf[Unit]) +
+ | f6( n4[Unit]) // "null"
+ """.stripMargin
+
+ assertEquals(run[String](code),
+ "0000null-0npe0npenull-()()()()null-0000null-0npe0npenull-()()()()null-0000null-0npe0npenull-()()()()null-00000-0npe0npenpe-()()()()null")
+ }
+}
diff --git a/test/junit/scala/PredefAutoboxingTest.scala b/test/junit/scala/lang/primitives/PredefAutoboxingTest.scala
index e5d8ded5d4..ab31a9e8f1 100644
--- a/test/junit/scala/PredefAutoboxingTest.scala
+++ b/test/junit/scala/lang/primitives/PredefAutoboxingTest.scala
@@ -1,12 +1,10 @@
-package scala
+package scala.lang.primitives
-import org.junit.Test
import org.junit.Assert._
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import scala.tools.testing.AssertUtil._
-
@RunWith(classOf[JUnit4])
class PredefAutoboxingTest {
@Test def unboxNullByte() =
diff --git a/test/junit/scala/StringContextTest.scala b/test/junit/scala/lang/stringinterpol/StringContextTest.scala
index b5af6de7eb..d2cb8149d7 100644
--- a/test/junit/scala/StringContextTest.scala
+++ b/test/junit/scala/lang/stringinterpol/StringContextTest.scala
@@ -1,15 +1,14 @@
-package scala
+package scala.lang.stringinterpol
import java.text.DecimalFormat
-import language.implicitConversions
-
-import org.junit.Test
import org.junit.Assert._
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
+import scala.language.implicitConversions
import scala.tools.testing.AssertUtil._
object StringContextTestUtils {
@@ -128,7 +127,7 @@ class StringContextTest {
val fff = new java.util.Formattable {
def formatTo(f: java.util.Formatter, g: Int, w: Int, p: Int) = f.format("4")
}
- import java.util.{ Calendar, Locale }
+ import java.util.{Calendar, Locale}
val c = Calendar.getInstance(Locale.US)
c.set(2012, Calendar.MAY, 26)
implicit def strToDate(x: String): Calendar = c
diff --git a/test/junit/scala/lang/traits/BytecodeTest.scala b/test/junit/scala/lang/traits/BytecodeTest.scala
new file mode 100644
index 0000000000..f47fc9c127
--- /dev/null
+++ b/test/junit/scala/lang/traits/BytecodeTest.scala
@@ -0,0 +1,282 @@
+package scala.lang.traits
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+import scala.collection.JavaConverters._
+import scala.tools.asm.Opcodes
+import scala.tools.asm.Opcodes._
+import scala.tools.asm.tree.ClassNode
+import scala.tools.partest.ASMConverters._
+import scala.tools.testing.BytecodeTesting
+import scala.tools.testing.BytecodeTesting._
+
+@RunWith(classOf[JUnit4])
+class BytecodeTest extends BytecodeTesting {
+ import compiler._
+
+ def checkForwarder(classes: Map[String, ClassNode], clsName: Symbol, target: String) = {
+ val List(f) = getMethods(classes(clsName.name), "f")
+ assertSameCode(f, List(VarOp(ALOAD, 0), Invoke(INVOKESPECIAL, target, "f", "()I", false), Op(IRETURN)))
+ }
+
+ @Test
+ def traitMethodForwarders(): Unit = {
+ val code =
+ """trait T1 { def f = 1 }
+ |trait T2 extends T1 { override def f = 2 }
+ |trait T3 { self: T1 => override def f = 3 }
+ |
+ |abstract class A1 { def f: Int }
+ |class A2 { def f: Int = 4 }
+ |
+ |trait T4 extends A1 { def f = 5 }
+ |trait T5 extends A2 { override def f = 6 }
+ |
+ |trait T6 { def f: Int }
+ |trait T7 extends T6 { abstract override def f = super.f + 1 }
+ |
+ |trait T8 { override def clone() = super.clone() }
+ |
+ |class A3 extends T1 { override def f = 7 }
+ |
+ |class C1 extends T1
+ |class C2 extends T2
+ |class C3 extends T1 with T2
+ |class C4 extends T2 with T1
+ |class C5 extends T1 with T3
+ |
+ |// traits extending a class that defines f
+ |class C6 extends T4
+ |class C7 extends T5
+ |class C8 extends A1 with T4
+ |class C9 extends A2 with T5
+ |
+ |// T6: abstract f in trait
+ |class C10 extends T6 with T1
+ |class C11 extends T6 with T2
+ |abstract class C12 extends A1 with T6
+ |class C13 extends A2 with T6
+ |class C14 extends T4 with T6
+ |class C15 extends T5 with T6
+ |
+ |// superclass overrides a trait method
+ |class C16 extends A3
+ |class C17 extends A3 with T1
+ |
+ |// abstract override
+ |class C18 extends T6 { def f = 22 }
+ |class C19 extends C18 with T7
+ |
+ |class C20 extends T8
+ """.stripMargin
+
+ val c = compileClasses(code).map(c => (c.name, c)).toMap
+
+ val noForwarder = List('C1, 'C2, 'C3, 'C4, 'C10, 'C11, 'C12, 'C13, 'C16, 'C17)
+ for (cn <- noForwarder) assertEquals(getMethods(c(cn.name), "f"), Nil)
+
+ checkForwarder(c, 'C5, "T3")
+ checkForwarder(c, 'C6, "T4")
+ checkForwarder(c, 'C7, "T5")
+ checkForwarder(c, 'C8, "T4")
+ checkForwarder(c, 'C9, "T5")
+ checkForwarder(c, 'C14, "T4")
+ checkForwarder(c, 'C15, "T5")
+ assertSameSummary(getMethod(c("C18"), "f"), List(BIPUSH, IRETURN))
+ checkForwarder(c, 'C19, "T7")
+ assertSameCode(getMethod(c("C19"), "T7$$super$f"), List(VarOp(ALOAD, 0), Invoke(INVOKESPECIAL, "C18", "f", "()I", false), Op(IRETURN)))
+ assertInvoke(getMethod(c("C20"), "clone"), "T8", "clone") // mixin forwarder
+ }
+
+ @Test
+ def noTraitMethodForwardersForOverloads(): Unit = {
+ val code =
+ """trait T1 { def f(x: Int) = 0 }
+ |trait T2 { def f(x: String) = 1 }
+ |class C extends T1 with T2
+ """.stripMargin
+ val List(c, t1, t2) = compileClasses(code)
+ assertEquals(getMethods(c, "f"), Nil)
+ }
+
+ @Test
+ def traitMethodForwardersForJavaDefaultMethods(): Unit = {
+ val j1 = ("interface J1 { int f(); }", "J1.java")
+ val j2 = ("interface J2 { default int f() { return 1; } }", "J2.java")
+ val j3 = ("interface J3 extends J1 { default int f() { return 2; } }", "J3.java")
+ val j4 = ("interface J4 extends J2 { default int f() { return 3; } }", "J4.java")
+ val code =
+ """trait T1 extends J2 { override def f = 4 }
+ |trait T2 { self: J2 => override def f = 5 }
+ |
+ |class K1 extends J2
+ |class K2 extends J1 with J2
+ |class K3 extends J2 with J1
+ |
+ |class K4 extends J3
+ |class K5 extends J3 with J1
+ |class K6 extends J1 with J3
+ |
+ |class K7 extends J4
+ |class K8 extends J4 with J2
+ |class K9 extends J2 with J4
+ |
+ |class K10 extends T1 with J2
+ |class K11 extends J2 with T1
+ |
+ |class K12 extends J2 with T2
+ """.stripMargin
+ val c = compileClasses(code, List(j1, j2, j3, j4)).map(c => (c.name, c)).toMap
+
+ val noForwarder = List('K1, 'K2, 'K3, 'K4, 'K5, 'K6, 'K7, 'K8, 'K9, 'K10, 'K11)
+ for (cn <- noForwarder) assertEquals(getMethods(c(cn.name), "f"), Nil)
+
+ checkForwarder(c, 'K12, "T2")
+ }
+
+ @Test
+ def invocationReceivers(): Unit = {
+ val List(c1, c2, t, u) = compileClasses(invocationReceiversTestCode.definitions("Object"))
+ // mixin forwarder in C1
+ assertSameCode(getMethod(c1, "clone"), List(VarOp(ALOAD, 0), Invoke(INVOKESPECIAL, "T", "clone", "()Ljava/lang/Object;", false), Op(ARETURN)))
+ assertInvoke(getMethod(c1, "f1"), "T", "clone")
+ assertInvoke(getMethod(c1, "f2"), "T", "clone")
+ assertInvoke(getMethod(c1, "f3"), "C1", "clone")
+ assertInvoke(getMethod(c2, "f1"), "T", "clone")
+ assertInvoke(getMethod(c2, "f2"), "T", "clone")
+ assertInvoke(getMethod(c2, "f3"), "C1", "clone")
+
+ val List(c1b, c2b, tb, ub) = compileClasses(invocationReceiversTestCode.definitions("String"))
+ def ms(c: ClassNode, n: String) = c.methods.asScala.toList.filter(_.name == n)
+ assert(ms(tb, "clone").length == 1)
+ assert(ms(ub, "clone").isEmpty)
+ val List(c1Clone) = ms(c1b, "clone")
+ assertEquals(c1Clone.desc, "()Ljava/lang/Object;")
+ assert((c1Clone.access | Opcodes.ACC_BRIDGE) != 0)
+ assertSameCode(convertMethod(c1Clone), List(VarOp(ALOAD, 0), Invoke(INVOKEVIRTUAL, "C1", "clone", "()Ljava/lang/String;", false), Op(ARETURN)))
+
+ def iv(m: Method) = getInstructions(c1b, "f1").collect({case i: Invoke => i})
+ assertSameCode(iv(getMethod(c1b, "f1")), List(Invoke(INVOKEINTERFACE, "T", "clone", "()Ljava/lang/String;", true)))
+ assertSameCode(iv(getMethod(c1b, "f2")), List(Invoke(INVOKEINTERFACE, "T", "clone", "()Ljava/lang/String;", true)))
+ // invokeinterface T.clone in C1 is OK here because it is not an override of Object.clone (different siganture)
+ assertSameCode(iv(getMethod(c1b, "f3")), List(Invoke(INVOKEINTERFACE, "T", "clone", "()Ljava/lang/String;", true)))
+ }
+
+ @Test
+ def invocationReceiversProtected(): Unit = {
+ // http://lrytz.github.io/scala-aladdin-bugtracker/displayItem.do%3Fid=455.html / 9954eaf
+ // also https://issues.scala-lang.org/browse/SI-1430 / 0bea2ab (same but with interfaces)
+ val aC =
+ """package a;
+ |/*package private*/ abstract class A {
+ | public int f() { return 1; }
+ | public int t;
+ |}
+ """.stripMargin
+ val bC =
+ """package a;
+ |public class B extends A { }
+ """.stripMargin
+ val iC =
+ """package a;
+ |/*package private*/ interface I { int f(); }
+ """.stripMargin
+ val jC =
+ """package a;
+ |public interface J extends I { }
+ """.stripMargin
+ val cC =
+ """package b
+ |class C {
+ | def f1(b: a.B) = b.f
+ | def f2(b: a.B) = { b.t = b.t + 1 }
+ | def f3(j: a.J) = j.f
+ |}
+ """.stripMargin
+ val c = compileClass(cC, javaCode = List((aC, "A.java"), (bC, "B.java"), (iC, "I.java"), (jC, "J.java")))
+ assertInvoke(getMethod(c, "f1"), "a/B", "f") // receiver needs to be B (A is not accessible in class C, package b)
+ assertInvoke(getMethod(c, "f3"), "a/J", "f") // receiver needs to be J
+ }
+
+ @Test
+ def specialInvocationReceivers(): Unit = {
+ val code =
+ """class C {
+ | def f1(a: Array[String]) = a.clone()
+ | def f2(a: Array[Int]) = a.hashCode()
+ | def f3(n: Nothing) = n.hashCode()
+ | def f4(n: Null) = n.toString()
+ |
+ |}
+ """.stripMargin
+ val c = compileClass(code)
+ assertInvoke(getMethod(c, "f1"), "[Ljava/lang/String;", "clone") // array descriptor as receiver
+ assertInvoke(getMethod(c, "f2"), "java/lang/Object", "hashCode") // object receiver
+ assertInvoke(getMethod(c, "f3"), "java/lang/Object", "hashCode")
+ assertInvoke(getMethod(c, "f4"), "java/lang/Object", "toString")
+ }
+
+ @Test
+ def superConstructorArgumentInSpecializedClass(): Unit = {
+ // see comment in SpecializeTypes.forwardCtorCall
+ val code = "case class C[@specialized(Int) T](_1: T)"
+ val List(c, cMod, cSpec) = compileClasses(code)
+ assertSameSummary(getMethod(cSpec, "<init>"),
+ // pass `null` to super constructor, no box-unbox, no Integer created
+ List(ALOAD, ILOAD, PUTFIELD, ALOAD, ACONST_NULL, "<init>", RETURN))
+ }
+
+}
+
+object invocationReceiversTestCode {
+ // if cloneType is more specific than Object (e.g., String), a bridge method is generated.
+ def definitions(cloneType: String) =
+ s"""trait T { override def clone(): $cloneType = "hi" }
+ |trait U extends T
+ |class C1 extends U with Cloneable {
+ | // The comments below are true when $cloneType is Object.
+ | // C1 gets a forwarder for clone that invokes T.clone. this is needed because JVM method
+ | // resolution always prefers class members, so it would resolve to Object.clone, even if
+ | // C1 is a subtype of the interface T which has an overriding default method for clone.
+ |
+ | // invokeinterface T.clone
+ | def f1 = (this: T).clone()
+ |
+ | // cannot invokeinterface U.clone (NoSuchMethodError). Object.clone would work here, but
+ | // not in the example in C2 (illegal access to protected). T.clone works in all cases and
+ | // resolves correctly.
+ | def f2 = (this: U).clone()
+ |
+ | // invokevirtual C1.clone()
+ | def f3 = (this: C1).clone()
+ |}
+ |
+ |class C2 {
+ | def f1(t: T) = t.clone() // invokeinterface T.clone
+ | def f2(t: U) = t.clone() // invokeinterface T.clone -- Object.clone would be illegal (protected, explained in C1)
+ | def f3(t: C1) = t.clone() // invokevirtual C1.clone -- Object.clone would be illegal
+ |}
+ """.stripMargin
+
+ val runCode =
+ """
+ |val r = new StringBuffer()
+ |val c1 = new C1
+ |r.append(c1.f1)
+ |r.append(c1.f2)
+ |r.append(c1.f3)
+ |val t = new T { }
+ |val u = new U { }
+ |val c2 = new C2
+ |r.append(c2.f1(t))
+ |r.append(c2.f1(u))
+ |r.append(c2.f1(c1))
+ |r.append(c2.f2(u))
+ |r.append(c2.f2(c1))
+ |r.append(c2.f3(c1))
+ |r.toString
+ """.stripMargin
+}
diff --git a/test/junit/scala/lang/traits/RunTest.scala b/test/junit/scala/lang/traits/RunTest.scala
new file mode 100644
index 0000000000..d27dc15e20
--- /dev/null
+++ b/test/junit/scala/lang/traits/RunTest.scala
@@ -0,0 +1,20 @@
+package scala.lang.traits
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+import scala.tools.testing.RunTesting
+
+@RunWith(classOf[JUnit4])
+class RunTest extends RunTesting {
+ import runner._
+
+ @Test
+ def invocationReceivers(): Unit = {
+ import invocationReceiversTestCode._
+ assertEquals(run[String](definitions("Object") + runCode), "hi" * 9)
+ assertEquals(run[String](definitions("String") + runCode), "hi" * 9) // bridge method for clone generated
+ }
+}
diff --git a/test/junit/scala/issues/RunTest.scala b/test/junit/scala/reflect/ClassOfTest.scala
index 0605947e63..520b14ccd4 100644
--- a/test/junit/scala/issues/RunTest.scala
+++ b/test/junit/scala/reflect/ClassOfTest.scala
@@ -1,36 +1,24 @@
-package scala.issues
+package scala.reflect
+import org.junit.Assert._
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.{AfterClass, BeforeClass, Test}
-import org.junit.Assert._
-
-import scala.reflect.runtime._
-import scala.tools.reflect.ToolBox
-import scala.tools.testing.ClearAfterClass
-object RunTest extends ClearAfterClass.Clearable {
- var toolBox = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
- override def clear(): Unit = { toolBox = null }
-
- // definitions for individual tests
+import scala.tools.testing.RunTesting
+object ClassOfTest {
class VC(val x: Any) extends AnyVal
}
@RunWith(classOf[JUnit4])
-class RunTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = RunTest
-
- def run[T](code: String): T = {
- val tb = RunTest.toolBox
- tb.eval(tb.parse(code)).asInstanceOf[T]
- }
+class ClassOfTest extends RunTesting {
+ import runner._
@Test
def classOfValueClassAlias(): Unit = {
val code =
- """import scala.issues.RunTest.VC
+ """import scala.reflect.ClassOfTest.VC
|type aVC = VC
|type aInt = Int
|type aInteger = Integer
@@ -84,7 +72,7 @@ class RunTest extends ClearAfterClass {
def t9702(): Unit = {
val code =
"""import javax.annotation.Resource
- |import scala.issues.RunTest.VC
+ |import scala.reflect.ClassOfTest.VC
|class C {
| type aList[K] = List[K]
| type aVC = VC
@@ -110,7 +98,7 @@ class RunTest extends ClearAfterClass {
val l = Class.forName("scala.collection.immutable.List")
val i = Integer.TYPE
val ig = new Integer(1).getClass
- val v = new RunTest.VC(1).getClass
+ val v = new ClassOfTest.VC(1).getClass
val ai = Array(1).getClass
val al = Array(List()).getClass
@@ -123,32 +111,6 @@ class RunTest extends ClearAfterClass {
}
@Test
- def annotationInfoNotErased(): Unit = {
- val code =
- """import javax.annotation.Resource
- |import scala.annotation.meta.getter
- |class C {
- | type Rg = Resource @getter
- | @(Resource @getter)(`type` = classOf[Int]) def a = 0
- | @Rg(`type` = classOf[Int]) def b = 0
- |}
- |val c = classOf[C]
- |def typeArg(meth: String) = c.getDeclaredMethod(meth).getDeclaredAnnotation(classOf[Resource]).`type`
- |List("a", "b") map typeArg
- |""".stripMargin
-
- val i = Integer.TYPE
- assertEquals(run[List[Class[_]]](code), List(i, i))
- }
-
- @Test
- def invocationReceivers(): Unit = {
- import invocationReceiversTestCode._
- assertEquals(run[String](definitions("Object") + runCode), "hi" * 9)
- assertEquals(run[String](definitions("String") + runCode), "hi" * 9) // bridge method for clone generated
- }
-
- @Test
def classOfUnitConstant(): Unit = {
val code =
"""abstract class A { def f: Class[_] }
diff --git a/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala
index 8b8e2b36de..0144fa7366 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala
@@ -1,37 +1,29 @@
package scala.tools.nsc
package backend.jvm
+import org.junit.Assert._
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
-import scala.tools.asm.Opcodes
-import org.junit.Assert._
-
-import scala.tools.nsc.backend.jvm.CodeGenTools._
-import scala.tools.testing.ClearAfterClass
-object BTypesTest extends ClearAfterClass.Clearable {
- var compiler = {
- val comp = newCompiler(extraArgs = "-Yopt:l:none")
- new comp.Run() // initializes some of the compiler
- comp.exitingDelambdafy(comp.scalaPrimitives.init()) // needed: it's only done when running the backend, and we don't actually run the compiler
- comp.exitingDelambdafy(comp.genBCode.bTypes.initializeCoreBTypes())
- comp
- }
- def clear(): Unit = { compiler = null }
-}
+import scala.tools.asm.Opcodes
+import scala.tools.testing.BytecodeTesting
@RunWith(classOf[JUnit4])
-class BTypesTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = BTypesTest
-
- val compiler = BTypesTest.compiler
- import compiler.genBCode.bTypes._
+class BTypesTest extends BytecodeTesting {
+ override def compilerArgs = "-Yopt:l:none"
+ import compiler.global
+ locally {
+ new global.Run() // initializes some of the compiler
+ global.exitingDelambdafy(global.scalaPrimitives.init()) // needed: it's only done when running the backend, and we don't actually run the compiler
+ global.exitingDelambdafy(global.genBCode.bTypes.initializeCoreBTypes())
+ }
+ import global.genBCode.bTypes._
- def classBTFS(sym: compiler.Symbol) = compiler.exitingDelambdafy(classBTypeFromSymbol(sym))
+ def classBTFS(sym: global.Symbol) = global.exitingDelambdafy(classBTypeFromSymbol(sym))
- def jlo = compiler.definitions.ObjectClass
- def jls = compiler.definitions.StringClass
+ def jlo = global.definitions.ObjectClass
+ def jls = global.definitions.StringClass
def o = classBTFS(jlo)
def s = classBTFS(jls)
def oArr = ArrayBType(o)
diff --git a/test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala b/test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala
new file mode 100644
index 0000000000..b2ee8b3a45
--- /dev/null
+++ b/test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala
@@ -0,0 +1,171 @@
+package scala.tools.nsc.backend.jvm
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+import scala.tools.asm.Opcodes._
+import scala.tools.partest.ASMConverters._
+import scala.tools.testing.BytecodeTesting
+import scala.tools.testing.BytecodeTesting._
+
+@RunWith(classOf[JUnit4])
+class BytecodeTest extends BytecodeTesting {
+ import compiler._
+
+ @Test
+ def t6288bJumpPosition(): Unit = {
+ val code =
+ """object Case3 { // 01
+ | def unapply(z: Any): Option[Int] = Some(-1) // 02
+ | def main(args: Array[String]) { // 03
+ | ("": Any) match { // 04
+ | case x : String => // 05
+ | println("case 0") // 06 println and jump at 6
+ | case _ => // 07
+ | println("default") // 08 println and jump at 8
+ | } // 09
+ | println("done") // 10
+ | }
+ |}
+ """.stripMargin
+ val List(mirror, module) = compileClasses(code)
+
+ val unapplyLineNumbers = getInstructions(module, "unapply").filter(_.isInstanceOf[LineNumber])
+ assert(unapplyLineNumbers == List(LineNumber(2, Label(0))), unapplyLineNumbers)
+
+ val expected = List(
+ LineNumber(4, Label(0)),
+ LineNumber(5, Label(5)),
+ Jump(IFEQ, Label(20)),
+
+ LineNumber(6, Label(11)),
+ Invoke(INVOKEVIRTUAL, "scala/Predef$", "println", "(Ljava/lang/Object;)V", false),
+ Jump(GOTO, Label(33)),
+
+ LineNumber(5, Label(20)),
+ Jump(GOTO, Label(24)),
+
+ LineNumber(8, Label(24)),
+ Invoke(INVOKEVIRTUAL, "scala/Predef$", "println", "(Ljava/lang/Object;)V", false),
+ Jump(GOTO, Label(33)),
+
+ LineNumber(10, Label(33)),
+ Invoke(INVOKEVIRTUAL, "scala/Predef$", "println", "(Ljava/lang/Object;)V", false)
+ )
+
+ val mainIns = getInstructions(module, "main") filter {
+ case _: LineNumber | _: Invoke | _: Jump => true
+ case _ => false
+ }
+ assertSameCode(mainIns, expected)
+ }
+
+ @Test
+ def bytecodeForBranches(): Unit = {
+ val code =
+ """class C {
+ | def t1(b: Boolean) = if (b) 1 else 2
+ | def t2(x: Int) = if (x == 393) 1 else 2
+ | def t3(a: Array[String], b: AnyRef) = a != b && b == a
+ | def t4(a: AnyRef) = a == null || null != a
+ | def t5(a: AnyRef) = (a eq null) || (null ne a)
+ | def t6(a: Int, b: Boolean) = if ((a == 10) && b || a != 1) 1 else 2
+ | def t7(a: AnyRef, b: AnyRef) = a == b
+ | def t8(a: AnyRef) = Nil == a || "" != a
+ |}
+ """.stripMargin
+
+ val c = compileClass(code)
+
+ // t1: no unnecessary GOTOs
+ assertSameCode(getMethod(c, "t1"), List(
+ VarOp(ILOAD, 1), Jump(IFEQ, Label(6)),
+ Op(ICONST_1), Jump(GOTO, Label(9)),
+ Label(6), Op(ICONST_2),
+ Label(9), Op(IRETURN)))
+
+ // t2: no unnecessary GOTOs
+ assertSameCode(getMethod(c, "t2"), List(
+ VarOp(ILOAD, 1), IntOp(SIPUSH, 393), Jump(IF_ICMPNE, Label(7)),
+ Op(ICONST_1), Jump(GOTO, Label(10)),
+ Label(7), Op(ICONST_2),
+ Label(10), Op(IRETURN)))
+
+ // t3: Array == is translated to reference equality, AnyRef == to null checks and equals
+ assertSameCode(getMethod(c, "t3"), List(
+ // Array ==
+ VarOp(ALOAD, 1), VarOp(ALOAD, 2), Jump(IF_ACMPEQ, Label(23)),
+ // AnyRef ==
+ VarOp(ALOAD, 2), VarOp(ALOAD, 1), VarOp(ASTORE, 3), Op(DUP), Jump(IFNONNULL, Label(14)),
+ Op(POP), VarOp(ALOAD, 3), Jump(IFNULL, Label(19)), Jump(GOTO, Label(23)),
+ Label(14), VarOp(ALOAD, 3), Invoke(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false), Jump(IFEQ, Label(23)),
+ Label(19), Op(ICONST_1), Jump(GOTO, Label(26)),
+ Label(23), Op(ICONST_0),
+ Label(26), Op(IRETURN)))
+
+ val t4t5 = List(
+ VarOp(ALOAD, 1), Jump(IFNULL, Label(6)),
+ VarOp(ALOAD, 1), Jump(IFNULL, Label(10)),
+ Label(6), Op(ICONST_1), Jump(GOTO, Label(13)),
+ Label(10), Op(ICONST_0),
+ Label(13), Op(IRETURN))
+
+ // t4: one side is known null, so just a null check on the other
+ assertSameCode(getMethod(c, "t4"), t4t5)
+
+ // t5: one side known null, so just a null check on the other
+ assertSameCode(getMethod(c, "t5"), t4t5)
+
+ // t6: no unnecessary GOTOs
+ assertSameCode(getMethod(c, "t6"), List(
+ VarOp(ILOAD, 1), IntOp(BIPUSH, 10), Jump(IF_ICMPNE, Label(7)),
+ VarOp(ILOAD, 2), Jump(IFNE, Label(12)),
+ Label(7), VarOp(ILOAD, 1), Op(ICONST_1), Jump(IF_ICMPEQ, Label(16)),
+ Label(12), Op(ICONST_1), Jump(GOTO, Label(19)),
+ Label(16), Op(ICONST_2),
+ Label(19), Op(IRETURN)))
+
+ // t7: universal equality
+ assertInvoke(getMethod(c, "t7"), "scala/runtime/BoxesRunTime", "equals")
+
+ // t8: no null checks invoking equals on modules and constants
+ assertSameCode(getMethod(c, "t8"), List(
+ Field(GETSTATIC, "scala/collection/immutable/Nil$", "MODULE$", "Lscala/collection/immutable/Nil$;"), VarOp(ALOAD, 1), Invoke(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false), Jump(IFNE, Label(10)),
+ Ldc(LDC, ""), VarOp(ALOAD, 1), Invoke(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false), Jump(IFNE, Label(14)),
+ Label(10), Op(ICONST_1), Jump(GOTO, Label(17)),
+ Label(14), Op(ICONST_0),
+ Label(17), Op(IRETURN)))
+ }
+
+ @Test // wrong local variable table for methods containing while loops
+ def t9179(): Unit = {
+ val code =
+ """class C {
+ | def t(): Unit = {
+ | var x = ""
+ | while (x != null) {
+ | foo()
+ | x = null
+ | }
+ | bar()
+ | }
+ | def foo(): Unit = ()
+ | def bar(): Unit = ()
+ |}
+ """.stripMargin
+ val c = compileClass(code)
+ val t = getMethod(c, "t")
+ val isFrameLine = (x: Instruction) => x.isInstanceOf[FrameEntry] || x.isInstanceOf[LineNumber]
+ assertSameCode(t.instructions.filterNot(isFrameLine), List(
+ Label(0), Ldc(LDC, ""), Label(3), VarOp(ASTORE, 1),
+ Label(5), VarOp(ALOAD, 1), Jump(IFNULL, Label(21)),
+ Label(10), VarOp(ALOAD, 0), Invoke(INVOKEVIRTUAL, "C", "foo", "()V", false), Label(14), Op(ACONST_NULL), VarOp(ASTORE, 1), Label(18), Jump(GOTO, Label(5)),
+ Label(21), VarOp(ALOAD, 0), Invoke(INVOKEVIRTUAL, "C", "bar", "()V", false), Label(26), Op(RETURN), Label(28)))
+ val labels = t.instructions collect { case l: Label => l }
+ val x = t.localVars.find(_.name == "x").get
+ assertEquals(x.start, labels(1))
+ assertEquals(x.end, labels(7))
+ }
+}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/DefaultMethodTest.scala b/test/junit/scala/tools/nsc/backend/jvm/DefaultMethodTest.scala
index 2ce9d21331..c9a958ee4f 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/DefaultMethodTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/DefaultMethodTest.scala
@@ -4,36 +4,29 @@ import org.junit.Assert._
import org.junit.Test
import scala.collection.JavaConverters
+import scala.collection.JavaConverters._
import scala.tools.asm.Opcodes
import scala.tools.asm.tree.ClassNode
-import scala.tools.nsc.backend.jvm.CodeGenTools._
-import JavaConverters._
-import scala.tools.testing.ClearAfterClass
-
-object DefaultMethodTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler()
- def clear(): Unit = { compiler = null }
-}
-
-class DefaultMethodTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = DefaultMethodTest
- val compiler = DefaultMethodTest.compiler
+import scala.tools.testing.BytecodeTesting
+import scala.tools.testing.BytecodeTesting._
+class DefaultMethodTest extends BytecodeTesting {
+ import compiler._
@Test
def defaultMethodsViaGenBCode(): Unit = {
- import compiler._
+ import global._
val code = "package pack { trait T { def foo: Int }}"
object makeFooDefaultMethod extends Transformer {
val Foo = TermName("foo")
/** Transforms a single tree. */
- override def transform(tree: compiler.Tree): compiler.Tree = tree match {
+ override def transform(tree: global.Tree): global.Tree = tree match {
case dd @ DefDef(_, Foo, _, _, _, _) =>
dd.symbol.setFlag(reflect.internal.Flags.JAVA_DEFAULTMETHOD)
copyDefDef(dd)(rhs = Literal(Constant(1)).setType(definitions.IntTpe))
case _ => super.transform(tree)
}
}
- val asmClasses: List[ClassNode] = readAsmClasses(compileTransformed(compiler)(code, Nil, makeFooDefaultMethod.transform(_)))
+ val asmClasses: List[ClassNode] = compiler.compileClassesTransformed(code, Nil, makeFooDefaultMethod.transform(_))
val foo = asmClasses.head.methods.iterator.asScala.toList.last
assertTrue("default method should not be abstract", (foo.access & Opcodes.ACC_ABSTRACT) == 0)
assertTrue("default method body emitted", foo.instructions.size() > 0)
diff --git a/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala b/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala
index 0cdc6ead10..7fdfb31577 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala
@@ -1,28 +1,23 @@
package scala.tools.nsc.backend.jvm
+import org.junit.Assert._
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Assert._
-import CodeGenTools._
+
import scala.tools.asm.Opcodes._
import scala.tools.partest.ASMConverters._
-import scala.tools.testing.ClearAfterClass
-
-object DirectCompileTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler(extraArgs = "-Yopt:l:method")
- def clear(): Unit = { compiler = null }
-}
+import scala.tools.testing.BytecodeTesting
+import scala.tools.testing.BytecodeTesting._
@RunWith(classOf[JUnit4])
-class DirectCompileTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = DirectCompileTest
-
- val compiler = DirectCompileTest.compiler
+class DirectCompileTest extends BytecodeTesting {
+ override def compilerArgs = "-Yopt:l:method"
+ import compiler._
@Test
def testCompile(): Unit = {
- val List(("C.class", bytes)) = compile(compiler)(
+ val List(("C.class", bytes)) = compileToBytes(
"""class C {
| def f = 1
|}
@@ -33,12 +28,12 @@ class DirectCompileTest extends ClearAfterClass {
@Test
def testCompileClasses(): Unit = {
- val List(cClass, cModuleClass) = compileClasses(compiler)("class C; object C")
+ val List(cClass, cModuleClass) = compileClasses("class C; object C")
assertTrue(cClass.name == "C")
assertTrue(cModuleClass.name == "C$")
- val List(dMirror, dModuleClass) = compileClasses(compiler)("object D")
+ val List(dMirror, dModuleClass) = compileClasses("object D")
assertTrue(dMirror.name == "D")
assertTrue(dModuleClass.name == "D$")
@@ -46,25 +41,23 @@ class DirectCompileTest extends ClearAfterClass {
@Test
def testCompileMethods(): Unit = {
- val List(f, g) = compileMethods(compiler)(
+ val List(f, g) = compileMethods(
"""def f = 10
|def g = f
""".stripMargin)
- assertTrue(f.name == "f")
- assertTrue(g.name == "g")
- assertSameCode(instructionsFromMethod(f).dropNonOp,
+ assertSameCode(f.instructions.dropNonOp,
List(IntOp(BIPUSH, 10), Op(IRETURN)))
- assertSameCode(instructionsFromMethod(g).dropNonOp,
+ assertSameCode(g.instructions.dropNonOp,
List(VarOp(ALOAD, 0), Invoke(INVOKEVIRTUAL, "C", "f", "()I", itf = false), Op(IRETURN)))
}
@Test
def testDropNonOpAliveLabels(): Unit = {
// makes sure that dropNoOp doesn't drop labels that are being used
- val List(f) = compileMethods(compiler)("""def f(x: Int) = if (x == 0) "a" else "b"""")
- assertSameCode(instructionsFromMethod(f).dropLinesFrames, List(
+ val is = compileInstructions("""def f(x: Int) = if (x == 0) "a" else "b"""")
+ assertSameCode(is.dropLinesFrames, List(
Label(0),
VarOp(ILOAD, 1),
Op(ICONST_0),
@@ -84,7 +77,7 @@ class DirectCompileTest extends ClearAfterClass {
val codeA = "class A { def f = 1 }"
val codeB = "class B extends A { def g = f }"
val List(a, b) = compileClassesSeparately(List(codeA, codeB))
- val ins = getSingleMethod(b, "g").instructions
+ val ins = getInstructions(b, "g")
assert(ins exists {
case Invoke(_, "B", "f", _, _) => true
case _ => false
@@ -93,6 +86,6 @@ class DirectCompileTest extends ClearAfterClass {
@Test
def compileErroneous(): Unit = {
- compileClasses(compiler)("class C { def f: String = 1 }", allowMessage = _.msg contains "type mismatch")
+ compileToBytes("class C { def f: String = 1 }", allowMessage = _.msg contains "type mismatch")
}
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala b/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala
index d29f6b0a13..ac2aab01dc 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala
@@ -1,30 +1,19 @@
package scala.tools.nsc.backend.jvm
import org.junit.Assert._
-import org.junit.{Assert, Test}
+import org.junit.Test
-import scala.tools.asm.{Handle, Opcodes}
-import scala.tools.asm.tree.InvokeDynamicInsnNode
-import scala.tools.nsc.backend.jvm.AsmUtils._
-import scala.tools.nsc.backend.jvm.CodeGenTools._
-import scala.tools.testing.ClearAfterClass
import scala.collection.JavaConverters._
+import scala.tools.asm.Handle
+import scala.tools.asm.tree.InvokeDynamicInsnNode
+import scala.tools.testing.BytecodeTesting
-object IndyLambdaTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler()
-
- def clear(): Unit = {
- compiler = null
- }
-}
-
-class IndyLambdaTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = IndyLambdaTest
- val compiler = IndyLambdaTest.compiler
+class IndyLambdaTest extends BytecodeTesting {
+ import compiler._
@Test def boxingBridgeMethodUsedSelectively(): Unit = {
def implMethodDescriptorFor(code: String): String = {
- val method = compileMethods(compiler)(s"""def f = $code """).find(_.name == "f").get
+ val method = compileAsmMethods(s"""def f = $code """).find(_.name == "f").get
val x = method.instructions.iterator.asScala.toList
x.flatMap {
case insn : InvokeDynamicInsnNode => insn.bsmArgs.collect { case h : Handle => h.getDesc }
@@ -57,17 +46,17 @@ class IndyLambdaTest extends ClearAfterClass {
assertEquals("(I)I", implMethodDescriptorFor("(x: Int) => x"))
// non-builtin sams are like specialized functions
- compileClasses(compiler)("class VC(private val i: Int) extends AnyVal; trait FunVC { def apply(a: VC): VC }")
+ compileToBytes("class VC(private val i: Int) extends AnyVal; trait FunVC { def apply(a: VC): VC }")
assertEquals("(I)I", implMethodDescriptorFor("((x: VC) => x): FunVC"))
- compileClasses(compiler)("trait Fun1[T, U] { def apply(a: T): U }")
+ compileToBytes("trait Fun1[T, U] { def apply(a: T): U }")
assertEquals(s"($obj)$str", implMethodDescriptorFor("(x => x.toString): Fun1[Int, String]"))
assertEquals(s"($obj)$obj", implMethodDescriptorFor("(x => println(x)): Fun1[Int, Unit]"))
assertEquals(s"($obj)$str", implMethodDescriptorFor("((x: VC) => \"\") : Fun1[VC, String]"))
assertEquals(s"($str)$obj", implMethodDescriptorFor("((x: String) => new VC(0)) : Fun1[String, VC]"))
- compileClasses(compiler)("trait Coll[A, Repr] extends Any")
- compileClasses(compiler)("final class ofInt(val repr: Array[Int]) extends AnyVal with Coll[Int, Array[Int]]")
+ compileToBytes("trait Coll[A, Repr] extends Any")
+ compileToBytes("final class ofInt(val repr: Array[Int]) extends AnyVal with Coll[Int, Array[Int]]")
assertEquals(s"([I)$obj", implMethodDescriptorFor("((xs: Array[Int]) => new ofInt(xs)): Array[Int] => Coll[Int, Array[Int]]"))
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/IndySammyTest.scala b/test/junit/scala/tools/nsc/backend/jvm/IndySammyTest.scala
index b9e45a7dc9..2bcbcc870c 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/IndySammyTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/IndySammyTest.scala
@@ -2,34 +2,20 @@ package scala.tools.nsc
package backend.jvm
import org.junit.Assert.assertEquals
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
import scala.tools.asm.Opcodes._
-import scala.tools.asm.tree._
import scala.tools.nsc.reporters.StoreReporter
-import CodeGenTools._
-import scala.tools.partest.ASMConverters
-import ASMConverters._
-
-import scala.tools.testing.ClearAfterClass
-
-object IndySammyTest extends ClearAfterClass.Clearable {
- var _compiler = newCompiler()
+import scala.tools.partest.ASMConverters._
+import scala.tools.testing.BytecodeTesting
+import scala.tools.testing.BytecodeTesting._
- def compile(scalaCode: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): List[ClassNode] =
- compileClasses(_compiler)(scalaCode, javaCode, allowMessage)
-
- def clear(): Unit = { _compiler = null }
-}
@RunWith(classOf[JUnit4])
-class IndySammyTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = IndySammyTest
- import IndySammyTest._
-
- val compiler = _compiler
+class IndySammyTest extends BytecodeTesting {
+ import compiler._
def funClassName(from: String, to: String) = s"Fun$from$to"
def classPrologue(from: String, to: String) =
@@ -53,13 +39,13 @@ class IndySammyTest extends ClearAfterClass {
def test(from: String, to: String, arg: String, body: String => String = x => x)
(expectedSig: String, lamBody: List[Instruction], appArgs: List[Instruction], ret: Instruction)
(allowMessage: StoreReporter#Info => Boolean = _ => false) = {
- val cls = compile(s"${classPrologue(from, to)}")
- val methodNodes = compileMethods(compiler)(lamDef(from, to, body) +";"+ appDef(arg), allowMessage)
+ val List(funClass, vcClass, vcCompanion) = compileClasses(s"${classPrologue(from, to)}")
+ val c = compileClass(s"class C { ${lamDef(from, to, body)}; ${appDef(arg)} }", allowMessage = allowMessage)
- val applySig = cls.head.methods.get(0).desc
- val anonfun = methodNodes.find(_.name contains "$anonfun$").map(convertMethod).get
- val lamInsn = methodNodes.find(_.name == "lam").map(instructionsFromMethod).get.dropNonOp
- val applyInvoke = methodNodes.find(_.name == "app").map(convertMethod).get
+ val applySig = getAsmMethod(funClass, "apply").desc
+ val anonfun = getMethod(c, "C$$$anonfun$1")
+ val lamInsn = getInstructions(c, "lam").dropNonOp
+ val applyInvoke = getMethod(c, "app")
assertEquals(expectedSig, applySig)
assert(lamInsn.length == 2 && lamInsn.head.isInstanceOf[InvokeDynamic], lamInsn)
@@ -72,7 +58,7 @@ class IndySammyTest extends ClearAfterClass {
}
// def testSpecial(lam: String, lamTp: String, arg: String)(allowMessage: StoreReporter#Info => Boolean = _ => false) = {
-// val cls = compile("trait Special[@specialized A] { def apply(a: A): A}" )
+// val cls = compileClasses("trait Special[@specialized A] { def apply(a: A): A}" )
// val methodNodes = compileMethods(compiler)(s"def lam : $lamTp = $lam" +";"+ appDef(arg), allowMessage)
//
// val anonfun = methodNodes.filter(_.name contains "$anonfun$").map(convertMethod)
@@ -154,7 +140,7 @@ class IndySammyTest extends ClearAfterClass {
// Tests ThisReferringMethodsTraverser
@Test
def testStaticIfNoThisReference: Unit = {
- val methodNodes = compileMethods(compiler)("def foo = () => () => () => 42")
+ val methodNodes = compileAsmMethods("def foo = () => () => () => 42")
methodNodes.forall(m => !m.name.contains("anonfun") || (m.access & ACC_STATIC) == ACC_STATIC)
}
}
diff --git a/test/junit/scala/issues/OptimizedBytecodeTest.scala b/test/junit/scala/tools/nsc/backend/jvm/OptimizedBytecodeTest.scala
index 1555e8945a..003162c1ad 100644
--- a/test/junit/scala/issues/OptimizedBytecodeTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/OptimizedBytecodeTest.scala
@@ -1,31 +1,18 @@
-package scala.issues
+package scala.tools.nsc.backend.jvm
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
-import scala.tools.asm.Opcodes._
-import org.junit.Assert._
-
-import scala.tools.nsc.backend.jvm.{AsmUtils, CodeGenTools}
-
-import CodeGenTools._
-import scala.tools.partest.ASMConverters
-import ASMConverters._
-import AsmUtils._
-import scala.tools.testing.ClearAfterClass
-
-object OptimizedBytecodeTest extends ClearAfterClass.Clearable {
- val args = "-Yopt:l:classpath -Yopt-warnings"
- var compiler = newCompiler(extraArgs = args)
- def clear(): Unit = { compiler = null }
-}
+import scala.tools.asm.Opcodes._
+import scala.tools.partest.ASMConverters._
+import scala.tools.testing.BytecodeTesting
+import scala.tools.testing.BytecodeTesting._
@RunWith(classOf[JUnit4])
-class OptimizedBytecodeTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = OptimizedBytecodeTest
-
- val compiler = OptimizedBytecodeTest.compiler
+class OptimizedBytecodeTest extends BytecodeTesting {
+ override def compilerArgs = "-Yopt:l:classpath -Yopt-warnings"
+ import compiler._
@Test
def t2171(): Unit = {
@@ -35,8 +22,8 @@ class OptimizedBytecodeTest extends ClearAfterClass {
| def t(): Unit = while (true) m("...")
|}
""".stripMargin
- val List(c) = compileClasses(compiler)(code)
- assertSameCode(getSingleMethod(c, "t"), List(Label(0), Jump(GOTO, Label(0))))
+ val c = compileClass(code)
+ assertSameCode(getMethod(c, "t"), List(Label(0), Jump(GOTO, Label(0))))
}
@Test
@@ -53,12 +40,12 @@ class OptimizedBytecodeTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val List(c) = compileClasses(compiler)(code)
+ val c = compileClass(code)
- assertSameSummary(getSingleMethod(c, "t"), List(
+ assertSameSummary(getMethod(c, "t"), List(
LDC, ASTORE, ALOAD /*0*/, ALOAD /*1*/, "C$$$anonfun$1", IRETURN))
- assertSameSummary(getSingleMethod(c, "C$$$anonfun$1"), List(LDC, "C$$$anonfun$2", IRETURN))
- assertSameSummary(getSingleMethod(c, "C$$$anonfun$2"), List(-1 /*A*/, GOTO /*A*/))
+ assertSameSummary(getMethod(c, "C$$$anonfun$1"), List(LDC, "C$$$anonfun$2", IRETURN))
+ assertSameSummary(getMethod(c, "C$$$anonfun$2"), List(-1 /*A*/, GOTO /*A*/))
}
@Test
@@ -79,8 +66,8 @@ class OptimizedBytecodeTest extends ClearAfterClass {
| def h(block: => Unit): Nothing = ???
|}
""".stripMargin
- val List(c, t, tMod) = compileClasses(compiler)(code, allowMessage = _.msg.contains("not be exhaustive"))
- assertSameSummary(getSingleMethod(c, "t"), List(GETSTATIC, "$qmark$qmark$qmark", ATHROW))
+ val List(c, t, tMod) = compileClasses(code, allowMessage = _.msg.contains("not be exhaustive"))
+ assertSameSummary(getMethod(c, "t"), List(GETSTATIC, "$qmark$qmark$qmark", ATHROW))
}
@Test
@@ -104,7 +91,7 @@ class OptimizedBytecodeTest extends ClearAfterClass {
|arguments expected by the callee ErrorHandler$::defaultIfIOException(Lscala/Function0;Lscala/Function0;)Ljava/lang/Object;. These values would be discarded
|when entering an exception handler declared in the inlined method.""".stripMargin
- compileClasses(compiler)(code, allowMessage = _.msg == msg)
+ compileClasses(code, allowMessage = _.msg == msg)
}
@Test
@@ -117,7 +104,7 @@ class OptimizedBytecodeTest extends ClearAfterClass {
| }
|}
""".stripMargin
- compileClasses(compiler)(code)
+ compileToBytes(code)
}
@Test
@@ -127,8 +114,8 @@ class OptimizedBytecodeTest extends ClearAfterClass {
|object Warmup { def filter[A](p: Any => Boolean): Any = filter[Any](p) }
""".stripMargin
val c2 = "class C { def t = warmup.Warmup.filter[Any](x => false) }"
- val List(c, _, _) = compileClassesSeparately(List(c1, c2), extraArgs = OptimizedBytecodeTest.args)
- assertInvoke(getSingleMethod(c, "t"), "warmup/Warmup$", "filter")
+ val List(c, _, _) = compileClassesSeparately(List(c1, c2), extraArgs = compilerArgs)
+ assertInvoke(getMethod(c, "t"), "warmup/Warmup$", "filter")
}
@Test
@@ -142,7 +129,7 @@ class OptimizedBytecodeTest extends ClearAfterClass {
| }
|}
""".stripMargin
- compileClasses(compiler)(code)
+ compileToBytes(code)
}
@Test
@@ -170,7 +157,7 @@ class OptimizedBytecodeTest extends ClearAfterClass {
| }
|}
""".stripMargin
- compileClasses(compiler)(code)
+ compileToBytes(code)
}
@Test
@@ -186,7 +173,7 @@ class OptimizedBytecodeTest extends ClearAfterClass {
| }
|}
""".stripMargin
- compileClasses(compiler)(code)
+ compileToBytes(code)
}
@Test
@@ -208,7 +195,7 @@ class OptimizedBytecodeTest extends ClearAfterClass {
| val NoContext = self.analyzer.NoContext
|}
""".stripMargin
- compileClasses(compiler)(code)
+ compileClasses(code)
}
@Test
@@ -225,8 +212,8 @@ class OptimizedBytecodeTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val List(c) = compileClasses(compiler)(code)
- assertSameSummary(getSingleMethod(c, "t"), List(
+ val c = compileClass(code)
+ assertSameSummary(getMethod(c, "t"), List(
ALOAD /*1*/, INSTANCEOF /*Some*/, IFNE /*A*/,
ALOAD /*0*/, "getInt", POP,
-1 /*A*/, BIPUSH, IRETURN))
@@ -244,8 +231,8 @@ class OptimizedBytecodeTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val List(c) = compileClasses(compiler)(code)
- assertSameSummary(getSingleMethod(c, "t"), List(
+ val c = compileClass(code)
+ assertSameSummary(getMethod(c, "t"), List(
-1 /*A*/, ILOAD /*1*/, TABLESWITCH,
-1, ALOAD, "pr", RETURN,
-1, ALOAD, "pr", RETURN,
@@ -268,9 +255,9 @@ class OptimizedBytecodeTest extends ClearAfterClass {
|}
""".stripMargin
- val cls = compileClassesSeparately(List(c1, c2), extraArgs = OptimizedBytecodeTest.args)
- val c = cls.find(_.name == "C").get
- assertSameSummary(getSingleMethod(c, "t"), List(
+ val cls = compileClassesSeparately(List(c1, c2), extraArgs = compilerArgs)
+ val c = findClass(cls, "C")
+ assertSameSummary(getMethod(c, "t"), List(
GETSTATIC, IFNONNULL, ACONST_NULL, ATHROW, // module load and null checks not yet eliminated
-1, ICONST_1, GETSTATIC, IFNONNULL, ACONST_NULL, ATHROW,
-1, ICONST_2, IADD, IRETURN))
@@ -307,11 +294,11 @@ class OptimizedBytecodeTest extends ClearAfterClass {
| def f2b() = identity(wrapper2(5)) // not inlined
|}
""".stripMargin
- val List(c) = compileClasses(compiler)(code, allowMessage = _.msg.contains("exception handler declared in the inlined method"))
- assertInvoke(getSingleMethod(c, "f1a"), "C", "C$$$anonfun$1")
- assertInvoke(getSingleMethod(c, "f1b"), "C", "wrapper1")
- assertInvoke(getSingleMethod(c, "f2a"), "C", "C$$$anonfun$3")
- assertInvoke(getSingleMethod(c, "f2b"), "C", "wrapper2")
+ val c = compileClass(code, allowMessage = _.msg.contains("exception handler declared in the inlined method"))
+ assertInvoke(getMethod(c, "f1a"), "C", "C$$$anonfun$1")
+ assertInvoke(getMethod(c, "f1b"), "C", "wrapper1")
+ assertInvoke(getMethod(c, "f2a"), "C", "C$$$anonfun$3")
+ assertInvoke(getMethod(c, "f2b"), "C", "wrapper2")
}
@Test
@@ -325,8 +312,8 @@ class OptimizedBytecodeTest extends ClearAfterClass {
| def t = mbarray_apply_minibox(null, 0)
|}
""".stripMargin
- val List(c) = compileClasses(compiler)(code)
- assertNoInvoke(getSingleMethod(c, "t"))
+ val c = compileClass(code)
+ assertNoInvoke(getMethod(c, "t"))
}
@Test
@@ -343,8 +330,8 @@ class OptimizedBytecodeTest extends ClearAfterClass {
|object Nill extends Listt
|class Listt
""".stripMargin
- val List(c, nil, nilMod, listt) = compileClasses(compiler)(code)
- assertInvoke(getSingleMethod(c, "t"), "C", "C$$$anonfun$1")
+ val List(c, nil, nilMod, listt) = compileClasses(code)
+ assertInvoke(getMethod(c, "t"), "C", "C$$$anonfun$1")
}
@Test
@@ -362,14 +349,14 @@ class OptimizedBytecodeTest extends ClearAfterClass {
| final def apply(a: Any): Any = throw new RuntimeException(key)
|}
""".stripMargin
- val List(c, f) = compileClasses(compiler)(code)
- assertInvoke(getSingleMethod(c, "crash"), "C", "map")
+ val List(c, f) = compileClasses(code)
+ assertInvoke(getMethod(c, "crash"), "C", "map")
}
@Test
def optimiseEnablesNewOpt(): Unit = {
val code = """class C { def t = (1 to 10) foreach println }"""
- val List(c) = readAsmClasses(compile(newCompiler(extraArgs = "-optimise -deprecation"))(code, allowMessage = _.msg.contains("is deprecated")))
- assertInvoke(getSingleMethod(c, "t"), "C", "C$$$anonfun$1") // range-foreach inlined from classpath
+ val List(c) = readAsmClasses(newCompiler(extraArgs = "-optimise -deprecation").compileToBytes(code, allowMessage = _.msg.contains("is deprecated")))
+ assertInvoke(getMethod(c, "t"), "C", "C$$$anonfun$1") // range-foreach inlined from classpath
}
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala b/test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala
index 2a9b8f7198..af2c8f9ce0 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala
@@ -1,28 +1,18 @@
package scala.tools.nsc
package backend.jvm
+import org.junit.Assert._
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
-import scala.tools.asm.Opcodes._
-import org.junit.Assert._
-import scala.tools.testing.AssertUtil._
-
-import CodeGenTools._
-import scala.tools.partest.ASMConverters
-import ASMConverters._
-import scala.tools.testing.ClearAfterClass
-
-object StringConcatTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler()
- def clear(): Unit = { compiler = null }
-}
+import scala.tools.partest.ASMConverters._
+import scala.tools.testing.BytecodeTesting
+import scala.tools.testing.BytecodeTesting._
@RunWith(classOf[JUnit4])
-class StringConcatTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = StringConcatTest
- val compiler = StringConcatTest.compiler
+class StringConcatTest extends BytecodeTesting {
+ import compiler._
@Test
def appendOverloadNoBoxing(): Unit = {
@@ -60,9 +50,9 @@ class StringConcatTest extends ClearAfterClass {
| chrs: Array[Char]) = this + str + v + z + c + b + s + i + f + l + d + sbuf + chsq + chrs
|}
""".stripMargin
- val List(c) = compileClasses(compiler)(code)
+ val c = compileClass(code)
- def invokeNameDesc(m: String): List[String] = getSingleMethod(c, m).instructions collect {
+ def invokeNameDesc(m: String): List[String] = getInstructions(c, m) collect {
case Invoke(_, _, name, desc, _) => name + desc
}
assertEquals(invokeNameDesc("t1"), List(
diff --git a/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala
index 571d84c872..b0a86dfd28 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala
@@ -2,41 +2,29 @@ package scala.tools.nsc
package backend.jvm
package analysis
+import org.junit.Assert._
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
-import scala.tools.asm.Opcodes._
-import org.junit.Assert._
-import CodeGenTools._
-import scala.tools.asm.tree.{AbstractInsnNode, MethodNode}
+import scala.collection.JavaConverters._
+import scala.tools.asm.tree.MethodNode
+import scala.tools.nsc.backend.jvm.AsmUtils._
import scala.tools.nsc.backend.jvm.BTypes._
-import scala.tools.partest.ASMConverters
-import ASMConverters._
-import scala.tools.testing.ClearAfterClass
import scala.tools.nsc.backend.jvm.opt.BytecodeUtils._
-import AsmUtils._
-
-import scala.collection.JavaConverters._
-
-object NullnessAnalyzerTest extends ClearAfterClass.Clearable {
- var noOptCompiler = newCompiler(extraArgs = "-Yopt:l:none")
-
- def clear(): Unit = {
- noOptCompiler = null
- }
-}
+import scala.tools.testing.BytecodeTesting
+import scala.tools.testing.BytecodeTesting._
@RunWith(classOf[JUnit4])
-class NullnessAnalyzerTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = NullnessAnalyzerTest
- val noOptCompiler = NullnessAnalyzerTest.noOptCompiler
- import noOptCompiler.genBCode.bTypes.backendUtils._
+class NullnessAnalyzerTest extends BytecodeTesting {
+ override def compilerArgs = "-Yopt:l:none"
+ import compiler._
+ import global.genBCode.bTypes.backendUtils._
- def newNullnessAnalyzer(methodNode: MethodNode, classInternalName: InternalName = "C") = new AsmAnalyzer(methodNode, classInternalName, new NullnessAnalyzer(noOptCompiler.genBCode.bTypes))
+ def newNullnessAnalyzer(methodNode: MethodNode, classInternalName: InternalName = "C") = new AsmAnalyzer(methodNode, classInternalName, new NullnessAnalyzer(global.genBCode.bTypes))
def testNullness(analyzer: AsmAnalyzer[NullnessValue], method: MethodNode, query: String, index: Int, nullness: NullnessValue): Unit = {
- for (i <- findInstr(method, query)) {
+ for (i <- findInstrs(method, query)) {
val r = analyzer.frameAt(i).getValue(index)
assertTrue(s"Expected: $nullness, found: $r. At instr ${textify(i)}", nullness == r)
}
@@ -62,7 +50,7 @@ class NullnessAnalyzerTest extends ClearAfterClass {
@Test
def showNullnessFramesTest(): Unit = {
- val List(m) = compileMethods(noOptCompiler)("def f = this.toString")
+ val m = compileAsmMethod("def f = this.toString")
// NOTE: the frame for an instruction represents the state *before* executing that instr.
// So in the frame for `ALOAD 0`, the stack is still empty.
@@ -80,14 +68,14 @@ class NullnessAnalyzerTest extends ClearAfterClass {
@Test
def thisNonNull(): Unit = {
- val List(m) = compileMethods(noOptCompiler)("def f = this.toString")
+ val m = compileAsmMethod("def f = this.toString")
val a = newNullnessAnalyzer(m)
testNullness(a, m, "ALOAD 0", 0, NotNullValue)
}
@Test
def instanceMethodCall(): Unit = {
- val List(m) = compileMethods(noOptCompiler)("def f(a: String) = a.trim")
+ val m = compileAsmMethod("def f(a: String) = a.trim")
val a = newNullnessAnalyzer(m)
testNullness(a, m, "INVOKEVIRTUAL java/lang/String.trim", 1, UnknownValue1)
testNullness(a, m, "ARETURN", 1, NotNullValue)
@@ -95,7 +83,7 @@ class NullnessAnalyzerTest extends ClearAfterClass {
@Test
def constructorCall(): Unit = {
- val List(m) = compileMethods(noOptCompiler)("def f = { val a = new Object; a.toString }")
+ val m = compileAsmMethod("def f = { val a = new Object; a.toString }")
val a = newNullnessAnalyzer(m)
// for reference, the output of showAllNullnessFrames(a, m) - note that the frame represents the state *before* executing the instr.
@@ -120,7 +108,7 @@ class NullnessAnalyzerTest extends ClearAfterClass {
@Test
def explicitNull(): Unit = {
- val List(m) = compileMethods(noOptCompiler)("def f = { var a: Object = null; a }")
+ val m = compileAsmMethod("def f = { var a: Object = null; a }")
val a = newNullnessAnalyzer(m)
for ((insn, index, nullness) <- List(
("+ACONST_NULL", 2, NullValue),
@@ -131,14 +119,14 @@ class NullnessAnalyzerTest extends ClearAfterClass {
@Test
def stringLiteralsNotNull(): Unit = {
- val List(m) = compileMethods(noOptCompiler)("""def f = { val a = "hi"; a.trim }""")
+ val m = compileAsmMethod("""def f = { val a = "hi"; a.trim }""")
val a = newNullnessAnalyzer(m)
testNullness(a, m, "+ASTORE 1", 1, NotNullValue)
}
@Test
def newArraynotNull() {
- val List(m) = compileMethods(noOptCompiler)("def f = { val a = new Array[Int](2); a(0) }")
+ val m = compileAsmMethod("def f = { val a = new Array[Int](2); a(0) }")
val a = newNullnessAnalyzer(m)
testNullness(a, m, "+NEWARRAY T_INT", 2, NotNullValue) // new array on stack
testNullness(a, m, "+ASTORE 1", 1, NotNullValue) // local var (a)
@@ -156,7 +144,7 @@ class NullnessAnalyzerTest extends ClearAfterClass {
| a.toString
|}
""".stripMargin
- val List(m) = compileMethods(noOptCompiler)(code)
+ val m = compileAsmMethod(code)
val a = newNullnessAnalyzer(m)
val toSt = "+INVOKEVIRTUAL java/lang/Object.toString"
testNullness(a, m, toSt, 3, UnknownValue1)
@@ -182,7 +170,7 @@ class NullnessAnalyzerTest extends ClearAfterClass {
| // d is null here, assinged in both branches.
|}
""".stripMargin
- val List(m) = compileMethods(noOptCompiler)(code)
+ val m = compileAsmMethod(code)
val a = newNullnessAnalyzer(m)
val trim = "INVOKEVIRTUAL java/lang/String.trim"
@@ -218,7 +206,7 @@ class NullnessAnalyzerTest extends ClearAfterClass {
| a.asInstanceOf[String].trim // the stack value (LOAD of local a) is still not-null after the CHECKCAST
|}
""".stripMargin
- val List(m) = compileMethods(noOptCompiler)(code)
+ val m = compileAsmMethod(code)
val a = newNullnessAnalyzer(m)
val instof = "+INSTANCEOF"
diff --git a/test/junit/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerTest.scala
index d54b8ac563..fc26785237 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerTest.scala
@@ -2,31 +2,23 @@ package scala.tools.nsc
package backend.jvm
package analysis
+import org.junit.Assert._
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Assert._
import scala.tools.asm.Opcodes
import scala.tools.asm.tree.AbstractInsnNode
+import scala.tools.nsc.backend.jvm.AsmUtils._
import scala.tools.partest.ASMConverters._
-import scala.tools.testing.ClearAfterClass
-import CodeGenTools._
-import AsmUtils._
-
-object ProdConsAnalyzerTest extends ClearAfterClass.Clearable {
- var noOptCompiler = newCompiler(extraArgs = "-Yopt:l:none")
-
- def clear(): Unit = {
- noOptCompiler = null
- }
-}
+import scala.tools.testing.BytecodeTesting
+import scala.tools.testing.BytecodeTesting._
@RunWith(classOf[JUnit4])
-class ProdConsAnalyzerTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = ProdConsAnalyzerTest
- val noOptCompiler = ProdConsAnalyzerTest.noOptCompiler
- import noOptCompiler.genBCode.bTypes.backendUtils._
+class ProdConsAnalyzerTest extends BytecodeTesting {
+ override def compilerArgs = "-Yopt:l:none"
+ import compiler._
+ import global.genBCode.bTypes.backendUtils._
def prodToString(producer: AbstractInsnNode) = producer match {
case p: InitialProducer => p.toString
@@ -57,9 +49,9 @@ class ProdConsAnalyzerTest extends ClearAfterClass {
@Test
def parameters(): Unit = {
- val List(m) = compileMethods(noOptCompiler)("def f = this.toString")
+ val m = compileAsmMethod("def f = this.toString")
val a = new ProdConsAnalyzer(m, "C")
- val call = findInstr(m, "INVOKEVIRTUAL").head
+ val call = findInstr(m, "INVOKEVIRTUAL")
testSingleInsn(a.producersForValueAt(call, 1), "ALOAD 0") // producer of stack value
testSingleInsn(a.producersForInputsOf(call), "ALOAD 0")
@@ -92,55 +84,55 @@ class ProdConsAnalyzerTest extends ClearAfterClass {
m.maxStack = 1
val a = new ProdConsAnalyzer(m, "C")
- val ifne = findInstr(m, "IFNE").head
+ val ifne = findInstr(m, "IFNE")
testSingleInsn(a.producersForValueAt(ifne, 1), "ParameterProducer")
- val ret = findInstr(m, "IRETURN").head
+ val ret = findInstr(m, "IRETURN")
testMultiInsns(a.producersForValueAt(ret, 1), List("ParameterProducer", "ISTORE 1"))
}
@Test
def branching(): Unit = {
- val List(m) = compileMethods(noOptCompiler)("def f(x: Int) = { var a = x; if (a == 0) a = 12; a }")
+ val m = compileAsmMethod("def f(x: Int) = { var a = x; if (a == 0) a = 12; a }")
val a = new ProdConsAnalyzer(m, "C")
- val List(ret) = findInstr(m, "IRETURN")
+ val ret = findInstr(m, "IRETURN")
testMultiInsns(a.producersForValueAt(ret, 2), List("ISTORE 2", "ISTORE 2"))
testMultiInsns(a.initialProducersForValueAt(ret, 2), List("BIPUSH 12", "ParameterProducer"))
- val List(bipush) = findInstr(m, "BIPUSH 12")
+ val bipush = findInstr(m, "BIPUSH 12")
testSingleInsn(a.consumersOfOutputsFrom(bipush), "ISTORE 2")
testSingleInsn(a.ultimateConsumersOfValueAt(bipush.getNext, 3), "IRETURN")
}
@Test
def checkCast(): Unit = {
- val List(m) = compileMethods(noOptCompiler)("def f(o: Object) = o.asInstanceOf[String]")
+ val m = compileAsmMethod("def f(o: Object) = o.asInstanceOf[String]")
val a = new ProdConsAnalyzer(m, "C")
- assert(findInstr(m, "CHECKCAST java/lang/String").length == 1)
+ assert(findInstrs(m, "CHECKCAST java/lang/String").length == 1)
- val List(ret) = findInstr(m, "ARETURN")
+ val ret = findInstr(m, "ARETURN")
testSingleInsn(a.initialProducersForInputsOf(ret), "ParameterProducer(1)")
}
@Test
def instanceOf(): Unit = {
- val List(m) = compileMethods(noOptCompiler)("def f(o: Object) = o.isInstanceOf[String]")
+ val m = compileAsmMethod("def f(o: Object) = o.isInstanceOf[String]")
val a = new ProdConsAnalyzer(m, "C")
- assert(findInstr(m, "INSTANCEOF java/lang/String").length == 1)
+ assert(findInstrs(m, "INSTANCEOF java/lang/String").length == 1)
- val List(ret) = findInstr(m, "IRETURN")
+ val ret = findInstr(m, "IRETURN")
testSingleInsn(a.initialProducersForInputsOf(ret), "INSTANCEOF")
}
@Test
def unInitLocal(): Unit = {
- val List(m) = compileMethods(noOptCompiler)("def f(b: Boolean) = { if (b) { var a = 0; println(a) }; 1 }")
+ val m = compileAsmMethod("def f(b: Boolean) = { if (b) { var a = 0; println(a) }; 1 }")
val a = new ProdConsAnalyzer(m, "C")
- val List(store) = findInstr(m, "ISTORE")
- val List(call) = findInstr(m, "INVOKEVIRTUAL")
- val List(ret) = findInstr(m, "IRETURN")
+ val store = findInstr(m, "ISTORE")
+ val call = findInstr(m, "INVOKEVIRTUAL")
+ val ret = findInstr(m, "IRETURN")
testSingleInsn(a.producersForValueAt(store, 2), "UninitializedLocalProducer(2)")
testSingleInsn(a.producersForValueAt(call, 2), "ISTORE")
@@ -149,11 +141,11 @@ class ProdConsAnalyzerTest extends ClearAfterClass {
@Test
def dupCopying(): Unit = {
- val List(m) = compileMethods(noOptCompiler)("def f = new Object")
+ val m = compileAsmMethod("def f = new Object")
val a = new ProdConsAnalyzer(m, "C")
- val List(newO) = findInstr(m, "NEW")
- val List(constr) = findInstr(m, "INVOKESPECIAL")
+ val newO = findInstr(m, "NEW")
+ val constr = findInstr(m, "INVOKESPECIAL")
testSingleInsn(a.producersForInputsOf(constr), "DUP")
testSingleInsn(a.initialProducersForInputsOf(constr), "NEW")
@@ -178,11 +170,11 @@ class ProdConsAnalyzerTest extends ClearAfterClass {
m.maxStack = 4
val a = new ProdConsAnalyzer(m, "C")
- val List(dup2) = findInstr(m, "DUP2")
- val List(add) = findInstr(m, "IADD")
- val List(swap) = findInstr(m, "SWAP")
- val List(store) = findInstr(m, "ISTORE")
- val List(ret) = findInstr(m, "IRETURN")
+ val dup2 = findInstr(m, "DUP2")
+ val add = findInstr(m, "IADD")
+ val swap = findInstr(m, "SWAP")
+ val store = findInstr(m, "ISTORE")
+ val ret = findInstr(m, "IRETURN")
testMultiInsns(a.producersForInputsOf(dup2), List("ILOAD", "ILOAD"))
testSingleInsn(a.consumersOfValueAt(dup2.getNext, 4), "IADD")
@@ -213,9 +205,9 @@ class ProdConsAnalyzerTest extends ClearAfterClass {
m.maxStack = 1
val a = new ProdConsAnalyzer(m, "C")
- val List(inc) = findInstr(m, "IINC")
- val List(load) = findInstr(m, "ILOAD")
- val List(ret) = findInstr(m, "IRETURN")
+ val inc = findInstr(m, "IINC")
+ val load = findInstr(m, "ILOAD")
+ val ret = findInstr(m, "IRETURN")
testSingleInsn(a.producersForInputsOf(inc), "ParameterProducer(1)")
testSingleInsn(a.consumersOfOutputsFrom(inc), "ILOAD")
@@ -231,12 +223,12 @@ class ProdConsAnalyzerTest extends ClearAfterClass {
@Test
def copyingInsns(): Unit = {
- val List(m) = compileMethods(noOptCompiler)("def f = 0l.asInstanceOf[Int]")
+ val m = compileAsmMethod("def f = 0l.asInstanceOf[Int]")
val a = new ProdConsAnalyzer(m, "C")
- val List(cnst) = findInstr(m, "LCONST_0")
- val List(l2i) = findInstr(m, "L2I") // l2i is not a copying instruction
- val List(ret) = findInstr(m, "IRETURN")
+ val cnst = findInstr(m, "LCONST_0")
+ val l2i = findInstr(m, "L2I") // l2i is not a copying instruction
+ val ret = findInstr(m, "IRETURN")
testSingleInsn(a.consumersOfOutputsFrom(cnst), "L2I")
testSingleInsn(a.ultimateConsumersOfOutputsFrom(cnst), "L2I")
@@ -272,10 +264,10 @@ class ProdConsAnalyzerTest extends ClearAfterClass {
m.maxStack = 2
val a = new ProdConsAnalyzer(m, "C")
- val List(iadd) = findInstr(m, "IADD")
+ val iadd = findInstr(m, "IADD")
val firstLoad = iadd.getPrevious.getPrevious
assert(firstLoad.getOpcode == ILOAD)
- val secondLoad = findInstr(m, "ISTORE").head.getPrevious
+ val secondLoad = findInstr(m, "ISTORE").getPrevious
assert(secondLoad.getOpcode == ILOAD)
testSingleInsn(a.producersForValueAt(iadd, 2), "ILOAD")
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/AnalyzerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/AnalyzerTest.scala
index 930f7f2f10..025248ac28 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/AnalyzerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/AnalyzerTest.scala
@@ -2,34 +2,21 @@ package scala.tools.nsc
package backend.jvm
package opt
+import org.junit.Assert._
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
-import org.junit.Assert._
-import scala.tools.asm.tree._
import scala.tools.asm.tree.analysis._
-import scala.tools.nsc.backend.jvm.analysis.{AliasingFrame, AliasingAnalyzer}
-
-import CodeGenTools._
-import scala.tools.partest.ASMConverters
-import ASMConverters._
-import AsmUtils._
-import BackendReporting._
-import BytecodeUtils._
-
-import scala.collection.JavaConverters._
-import scala.tools.testing.ClearAfterClass
-
-object AnalyzerTest extends ClearAfterClass.Clearable {
- var noOptCompiler = newCompiler(extraArgs = "-Yopt:l:none")
- def clear(): Unit = { noOptCompiler = null }
-}
+import scala.tools.nsc.backend.jvm.analysis.{AliasingAnalyzer, AliasingFrame}
+import scala.tools.nsc.backend.jvm.opt.BytecodeUtils._
+import scala.tools.testing.BytecodeTesting
+import scala.tools.testing.BytecodeTesting._
@RunWith(classOf[JUnit4])
-class AnalyzerTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = AnalyzerTest
- val noOptCompiler = AnalyzerTest.noOptCompiler
+class AnalyzerTest extends BytecodeTesting {
+ override def compilerArgs = "-Yopt:l:none"
+ import compiler._
@Test
def aliasingOfPrimitives(): Unit = {
@@ -45,17 +32,17 @@ class AnalyzerTest extends ClearAfterClass {
|}
""".stripMargin
- val List(c) = compileClasses(noOptCompiler)(code)
+ val c = compileClass(code)
val a = new AliasingAnalyzer(new BasicInterpreter)
- val f = findAsmMethod(c, "f")
+ val f = getAsmMethod(c, "f")
a.analyze("C", f)
- val List(_, i2l) = findInstr(f, "I2L")
+ val List(_, i2l) = findInstrs(f, "I2L")
val aliasesAtI2l = a.frameAt(i2l, f).asInstanceOf[AliasingFrame[_]].aliases
assertEquals(aliasesAtI2l(1).iterator.toList, List(1, 8, 9)) // a, e and stack top
assertEquals(aliasesAtI2l(4).iterator.toList, List(4, 6))
- val List(add) = findInstr(f, "LADD")
+ val add = findInstr(f, "LADD")
val aliasesAtAdd = a.frameAt(add, f).asInstanceOf[AliasingFrame[_]].aliases
assertEquals(aliasesAtAdd(1).iterator.toList, List(1, 8)) // after i2l the value on the stack is no longer an alias
assertEquals(aliasesAtAdd(4).iterator.toList, List(4, 6, 10)) // c, d and stack top
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala
index aba0aab038..e7aea71e72 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala
@@ -2,37 +2,29 @@ package scala.tools.nsc
package backend.jvm
package opt
+import org.junit.{Ignore, Test}
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
-import scala.tools.asm.Opcodes._
-import org.junit.Assert._
+import scala.tools.asm.Opcodes._
import scala.tools.nsc.backend.jvm.BTypes.InternalName
-import scala.tools.testing.AssertUtil._
-
-import CodeGenTools._
-import scala.tools.partest.ASMConverters
-import ASMConverters._
-
-import BackendReporting._
-
-import scala.collection.JavaConverters._
+import scala.tools.nsc.backend.jvm.BackendReporting._
+import scala.tools.testing.BytecodeTesting
@RunWith(classOf[JUnit4])
-class BTypesFromClassfileTest {
+class BTypesFromClassfileTest extends BytecodeTesting {
// inliner enabled -> inlineInfos are collected (and compared) in ClassBTypes
- val compiler = newCompiler(extraArgs = "-Yopt:inline-global")
+ override def compilerArgs = "-Yopt:inline-global"
- import compiler._
+ import compiler.global._
import definitions._
import genBCode.bTypes
import bTypes._
- def duringBackend[T](f: => T) = compiler.exitingDelambdafy(f)
+ def duringBackend[T](f: => T) = global.exitingDelambdafy(f)
- val run = new compiler.Run() // initializes some of the compiler
- duringBackend(compiler.scalaPrimitives.init()) // needed: it's only done when running the backend, and we don't actually run the compiler
+ val run = new global.Run() // initializes some of the compiler
+ duringBackend(global.scalaPrimitives.init()) // needed: it's only done when running the backend, and we don't actually run the compiler
duringBackend(bTypes.initializeCoreBTypes())
def clearCache() = bTypes.classBTypeFromInternalName.clear()
@@ -91,7 +83,9 @@ class BTypesFromClassfileTest {
sameBType(fromSymbol, fromClassfile)
}
- @Test
+ // Can be enabled when using 2.12.0-M5 as starr. This test works under a full boostrap, but not
+ // when compiled with M4.
+ @Test @Ignore
def compareClassBTypes(): Unit = {
// Note that not only these classes are tested, but also all their parents and all nested
// classes in their InnerClass attributes.
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala
index 1d30e42e3c..630416a925 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala
@@ -2,52 +2,38 @@ package scala.tools.nsc
package backend.jvm
package opt
+import org.junit.Assert._
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
+
+import scala.collection.JavaConverters._
import scala.collection.generic.Clearable
import scala.collection.immutable.IntMap
-import scala.tools.asm.Opcodes._
-import org.junit.Assert._
-
import scala.tools.asm.tree._
-import scala.tools.asm.tree.analysis._
+import scala.tools.nsc.backend.jvm.BackendReporting._
import scala.tools.nsc.reporters.StoreReporter
-import scala.tools.testing.AssertUtil._
-
-import CodeGenTools._
-import scala.tools.partest.ASMConverters
-import ASMConverters._
-import AsmUtils._
-import BackendReporting._
-
-import scala.collection.JavaConverters._
-import scala.tools.testing.ClearAfterClass
-
-object CallGraphTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler(extraArgs = "-Yopt:inline-global -Yopt-warnings")
- def clear(): Unit = { compiler = null }
-
- // allows inspecting the caches after a compilation run
- val notPerRun: List[Clearable] = List(
- compiler.genBCode.bTypes.classBTypeFromInternalName,
- compiler.genBCode.bTypes.byteCodeRepository.compilingClasses,
- compiler.genBCode.bTypes.byteCodeRepository.parsedClasses,
- compiler.genBCode.bTypes.callGraph.callsites)
- notPerRun foreach compiler.perRunCaches.unrecordCache
-}
+import scala.tools.testing.BytecodeTesting
+import scala.tools.testing.BytecodeTesting._
@RunWith(classOf[JUnit4])
-class CallGraphTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = CallGraphTest
+class CallGraphTest extends BytecodeTesting {
+ override def compilerArgs = "-Yopt:inline-global -Yopt-warnings"
+ import compiler._
+ import global.genBCode.bTypes
+ val notPerRun: List[Clearable] = List(
+ bTypes.classBTypeFromInternalName,
+ bTypes.byteCodeRepository.compilingClasses,
+ bTypes.byteCodeRepository.parsedClasses,
+ bTypes.callGraph.callsites)
+ notPerRun foreach global.perRunCaches.unrecordCache
- val compiler = CallGraphTest.compiler
- import compiler.genBCode.bTypes._
+ import global.genBCode.bTypes._
import callGraph._
def compile(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): List[ClassNode] = {
- CallGraphTest.notPerRun.foreach(_.clear())
- compileClasses(compiler)(code, allowMessage = allowMessage).map(c => byteCodeRepository.classNode(c.name).get)
+ notPerRun.foreach(_.clear())
+ compileClasses(code, allowMessage = allowMessage).map(c => byteCodeRepository.classNode(c.name).get)
}
def callsInMethod(methodNode: MethodNode): List[MethodInsnNode] = methodNode.instructions.iterator.asScala.collect({
@@ -118,10 +104,10 @@ class CallGraphTest extends ClearAfterClass {
val List(cCls, cMod, dCls, testCls) = compile(code, checkMsg)
assert(msgCount == 6, msgCount)
- val List(cf1, cf2, cf3, cf4, cf5, cf6, cf7) = findAsmMethods(cCls, _.startsWith("f"))
- val List(df1, df3) = findAsmMethods(dCls, _.startsWith("f"))
- val g1 = findAsmMethod(cMod, "g1")
- val List(t1, t2) = findAsmMethods(testCls, _.startsWith("t"))
+ val List(cf1, cf2, cf3, cf4, cf5, cf6, cf7) = getAsmMethods(cCls, _.startsWith("f"))
+ val List(df1, df3) = getAsmMethods(dCls, _.startsWith("f"))
+ val g1 = getAsmMethod(cMod, "g1")
+ val List(t1, t2) = getAsmMethods(testCls, _.startsWith("t"))
val List(cf1Call, cf2Call, cf3Call, cf4Call, cf5Call, cf6Call, cf7Call, cg1Call) = callsInMethod(t1)
val List(df1Call, df2Call, df3Call, df4Call, df5Call, df6Call, df7Call, dg1Call) = callsInMethod(t2)
@@ -157,7 +143,7 @@ class CallGraphTest extends ClearAfterClass {
|}
""".stripMargin
val List(c) = compile(code)
- val m = findAsmMethod(c, "m")
+ val m = getAsmMethod(c, "m")
val List(fn) = callsInMethod(m)
val forNameMeth = byteCodeRepository.methodNode("java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;").get._1
val classTp = classBTypeFromInternalName("java/lang/Class")
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala
index 12bfba71a8..218b02f822 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala
@@ -2,41 +2,19 @@ package scala.tools.nsc
package backend.jvm
package opt
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
-import scala.collection.generic.Clearable
-import scala.collection.mutable.ListBuffer
-import scala.reflect.internal.util.BatchSourceFile
-import scala.tools.asm.Opcodes._
-import org.junit.Assert._
-
-import scala.tools.asm.tree._
-import scala.tools.asm.tree.analysis._
-import scala.tools.nsc.io._
-import scala.tools.nsc.reporters.StoreReporter
-import scala.tools.testing.AssertUtil._
-
-import CodeGenTools._
-import scala.tools.partest.ASMConverters
-import ASMConverters._
-import AsmUtils._
-import BackendReporting._
-
-import scala.collection.JavaConverters._
-import scala.tools.testing.ClearAfterClass
-
-object ClosureOptimizerTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler(extraArgs = "-Yopt:l:classpath -Yopt-warnings:_")
- def clear(): Unit = { compiler = null }
-}
+import scala.tools.asm.Opcodes._
+import scala.tools.partest.ASMConverters._
+import scala.tools.testing.BytecodeTesting
+import scala.tools.testing.BytecodeTesting._
@RunWith(classOf[JUnit4])
-class ClosureOptimizerTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = ClosureOptimizerTest
-
- val compiler = ClosureOptimizerTest.compiler
+class ClosureOptimizerTest extends BytecodeTesting {
+ override def compilerArgs = "-Yopt:l:classpath -Yopt-warnings:_"
+ import compiler._
@Test
def nothingTypedClosureBody(): Unit = {
@@ -48,9 +26,9 @@ class ClosureOptimizerTest extends ClearAfterClass {
|}
""".stripMargin
- val List(c) = compileClasses(compiler)(code)
- val t = findAsmMethod(c, "t")
- val List(bodyCall) = findInstr(t, "INVOKESTATIC C.C$$$anonfun$1 ()Lscala/runtime/Nothing$")
+ val c = compileClass(code)
+ val t = getAsmMethod(c, "t")
+ val bodyCall = findInstr(t, "INVOKESTATIC C.C$$$anonfun$1 ()Lscala/runtime/Nothing$")
assert(bodyCall.getNext.getOpcode == ATHROW)
}
@@ -64,9 +42,9 @@ class ClosureOptimizerTest extends ClearAfterClass {
|}
""".stripMargin
- val List(c) = compileClasses(compiler)(code)
- val t = findAsmMethod(c, "t")
- val List(bodyCall) = findInstr(t, "INVOKESTATIC C.C$$$anonfun$1 ()Lscala/runtime/Null$")
+ val c = compileClass(code)
+ val t = getAsmMethod(c, "t")
+ val bodyCall = findInstr(t, "INVOKESTATIC C.C$$$anonfun$1 ()Lscala/runtime/Null$")
assert(bodyCall.getNext.getOpcode == POP)
assert(bodyCall.getNext.getNext.getOpcode == ACONST_NULL)
}
@@ -81,8 +59,8 @@ class ClosureOptimizerTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val List(c) = compileClasses(compiler)(code)
- assertSameCode(getSingleMethod(c, "t"),
+ val c = compileClass(code)
+ assertSameCode(getMethod(c, "t"),
List(VarOp(ALOAD, 1), Invoke(INVOKEVIRTUAL, "scala/collection/immutable/List", "head", "()Ljava/lang/Object;", false),
TypeOp(CHECKCAST, "java/lang/String"), Invoke(INVOKESTATIC, "C", "C$$$anonfun$1", "(Ljava/lang/String;)Ljava/lang/String;", false),
Op(ARETURN)))
@@ -102,7 +80,7 @@ class ClosureOptimizerTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val List(c) = compileClasses(compiler)(code)
- assertSameSummary(getSingleMethod(c, "t"), List(NEW, DUP, LDC, "<init>", ATHROW))
+ val c = compileClass(code)
+ assertSameSummary(getMethod(c, "t"), List(NEW, DUP, LDC, "<init>", ATHROW))
}
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/CompactLocalVariablesTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/CompactLocalVariablesTest.scala
index ac1b759fe2..c3748a05bd 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/CompactLocalVariablesTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/CompactLocalVariablesTest.scala
@@ -2,23 +2,21 @@ package scala.tools.nsc
package backend.jvm
package opt
+import org.junit.Assert._
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
-import scala.tools.asm.Opcodes._
-import org.junit.Assert._
-import CodeGenTools._
-import scala.tools.partest.ASMConverters
-import ASMConverters._
+import scala.tools.partest.ASMConverters._
+import scala.tools.testing.BytecodeTesting._
+import scala.tools.testing.ClearAfterClass
@RunWith(classOf[JUnit4])
-class CompactLocalVariablesTest {
-
+class CompactLocalVariablesTest extends ClearAfterClass {
// recurse-unreachable-jumps is required for eliminating catch blocks, in the first dce round they
// are still live.only after eliminating the empty handler the catch blocks become unreachable.
- val methodOptCompiler = newCompiler(extraArgs = "-Yopt:unreachable-code,compact-locals")
- val noCompactVarsCompiler = newCompiler(extraArgs = "-Yopt:unreachable-code")
+ val methodOptCompiler = cached("methodOptCompiler", () => newCompiler(extraArgs = "-Yopt:unreachable-code,compact-locals"))
+ val noCompactVarsCompiler = cached("noCompactVarsCompiler", () => newCompiler(extraArgs = "-Yopt:unreachable-code"))
@Test
def compactUnused(): Unit = {
@@ -58,8 +56,8 @@ class CompactLocalVariablesTest {
|}
|""".stripMargin
- val List(noCompact) = compileMethods(noCompactVarsCompiler)(code)
- val List(withCompact) = compileMethods(methodOptCompiler)(code)
+ val noCompact = noCompactVarsCompiler.compileAsmMethod(code)
+ val withCompact = methodOptCompiler.compileAsmMethod(code)
// code is the same, except for local var indices
assertTrue(noCompact.instructions.size == withCompact.instructions.size)
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala
index 22aed4207f..3324058cb7 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala
@@ -2,32 +2,23 @@ package scala.tools.nsc
package backend.jvm
package opt
+import org.junit.Assert._
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
+
import scala.tools.asm.Opcodes._
-import org.junit.Assert._
+import scala.tools.partest.ASMConverters._
+import scala.tools.testing.BytecodeTesting
+import scala.tools.testing.BytecodeTesting._
-import CodeGenTools._
-import scala.tools.partest.ASMConverters
-import ASMConverters._
-import scala.tools.testing.ClearAfterClass
-
-object EmptyExceptionHandlersTest extends ClearAfterClass.Clearable {
- var noOptCompiler = newCompiler(extraArgs = "-Yopt:l:none")
- var dceCompiler = newCompiler(extraArgs = "-Yopt:unreachable-code")
- def clear(): Unit = {
- noOptCompiler = null
- dceCompiler = null
- }
-}
@RunWith(classOf[JUnit4])
-class EmptyExceptionHandlersTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = EmptyExceptionHandlersTest
+class EmptyExceptionHandlersTest extends BytecodeTesting {
+ override def compilerArgs = "-Yopt:unreachable-code"
+ def dceCompiler = compiler
- val noOptCompiler = EmptyExceptionHandlersTest.noOptCompiler
- val dceCompiler = EmptyExceptionHandlersTest.dceCompiler
+ val noOptCompiler = cached("noOptCompiler", () => newCompiler(extraArgs = "-Yopt:l:none"))
val exceptionDescriptor = "java/lang/Exception"
@@ -69,8 +60,8 @@ class EmptyExceptionHandlersTest extends ClearAfterClass {
def eliminateUnreachableHandler(): Unit = {
val code = "def f: Unit = try { } catch { case _: Exception => println(0) }; println(1)"
- assertTrue(singleMethod(noOptCompiler)(code).handlers.length == 1)
- val optMethod = singleMethod(dceCompiler)(code)
+ assertTrue(noOptCompiler.compileMethod(code).handlers.length == 1)
+ val optMethod = dceCompiler.compileMethod(code)
assertTrue(optMethod.handlers.isEmpty)
val code2 =
@@ -82,7 +73,7 @@ class EmptyExceptionHandlersTest extends ClearAfterClass {
| println(2)
|}""".stripMargin
- assertTrue(singleMethod(dceCompiler)(code2).handlers.isEmpty)
+ assertTrue(dceCompiler.compileMethod(code2).handlers.isEmpty)
}
@Test
@@ -94,6 +85,6 @@ class EmptyExceptionHandlersTest extends ClearAfterClass {
| catch { case _: Exception => 2 }
|}""".stripMargin
- assertTrue(singleMethod(dceCompiler)(code).handlers.length == 1)
+ assertTrue(dceCompiler.compileMethod(code).handlers.length == 1)
}
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyLabelsAndLineNumbersTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyLabelsAndLineNumbersTest.scala
index 7283e20745..d57d44f2a3 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyLabelsAndLineNumbersTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyLabelsAndLineNumbersTest.scala
@@ -2,16 +2,16 @@ package scala.tools.nsc
package backend.jvm
package opt
+import org.junit.Assert._
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
-import scala.tools.asm.Opcodes._
-import org.junit.Assert._
-import scala.tools.testing.AssertUtil._
-import CodeGenTools._
+import scala.tools.asm.Opcodes._
import scala.tools.partest.ASMConverters
-import ASMConverters._
+import scala.tools.partest.ASMConverters._
+import scala.tools.testing.AssertUtil._
+import scala.tools.testing.BytecodeTesting._
@RunWith(classOf[JUnit4])
class EmptyLabelsAndLineNumbersTest {
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala
index 23386bb5ae..e45d7139a3 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala
@@ -2,42 +2,31 @@ package scala.tools.nsc
package backend.jvm
package opt
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
-import scala.collection.generic.Clearable
-import org.junit.Assert._
-
-import CodeGenTools._
-import scala.tools.partest.ASMConverters
-import ASMConverters._
-import AsmUtils._
-import scala.tools.testing.ClearAfterClass
-
-import BackendReporting._
import scala.collection.JavaConverters._
-
-object InlineInfoTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler(extraArgs = "-Yopt:l:classpath")
- def clear(): Unit = { compiler = null }
-
- def notPerRun: List[Clearable] = List(
- compiler.genBCode.bTypes.classBTypeFromInternalName,
- compiler.genBCode.bTypes.byteCodeRepository.compilingClasses,
- compiler.genBCode.bTypes.byteCodeRepository.parsedClasses)
- notPerRun foreach compiler.perRunCaches.unrecordCache
-}
+import scala.collection.generic.Clearable
+import scala.tools.nsc.backend.jvm.BackendReporting._
+import scala.tools.testing.BytecodeTesting
@RunWith(classOf[JUnit4])
-class InlineInfoTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = InlineInfoTest
+class InlineInfoTest extends BytecodeTesting {
+ import compiler.global
+ import global.genBCode.bTypes
+
+ override def compilerArgs = "-Yopt:l:classpath"
- val compiler = InlineInfoTest.compiler
+ def notPerRun: List[Clearable] = List(
+ bTypes.classBTypeFromInternalName,
+ bTypes.byteCodeRepository.compilingClasses,
+ bTypes.byteCodeRepository.parsedClasses)
+ notPerRun foreach global.perRunCaches.unrecordCache
def compile(code: String) = {
- InlineInfoTest.notPerRun.foreach(_.clear())
- compileClasses(compiler)(code)
+ notPerRun.foreach(_.clear())
+ compiler.compileClasses(code)
}
@Test
@@ -61,11 +50,11 @@ class InlineInfoTest extends ClearAfterClass {
""".stripMargin
val classes = compile(code)
- val fromSyms = classes.map(c => compiler.genBCode.bTypes.classBTypeFromInternalName(c.name).info.get.inlineInfo)
+ val fromSyms = classes.map(c => global.genBCode.bTypes.classBTypeFromInternalName(c.name).info.get.inlineInfo)
val fromAttrs = classes.map(c => {
assert(c.attrs.asScala.exists(_.isInstanceOf[InlineInfoAttribute]), c.attrs)
- compiler.genBCode.bTypes.inlineInfoFromClassfile(c)
+ global.genBCode.bTypes.inlineInfoFromClassfile(c)
})
assert(fromSyms == fromAttrs)
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala
index 1597c75a7e..f0913f3631 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala
@@ -2,49 +2,21 @@ package scala.tools.nsc
package backend.jvm
package opt
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
-import scala.collection.generic.Clearable
-import scala.collection.mutable.ListBuffer
-import scala.reflect.internal.util.BatchSourceFile
-import scala.tools.asm.Opcodes._
-import org.junit.Assert._
-
-import scala.tools.asm.tree._
-import scala.tools.asm.tree.analysis._
-import scala.tools.nsc.io._
-import scala.tools.nsc.reporters.StoreReporter
-import scala.tools.testing.AssertUtil._
-
-import CodeGenTools._
-import scala.tools.partest.ASMConverters
-import ASMConverters._
-import AsmUtils._
-
-import BackendReporting._
-
-import scala.collection.JavaConverters._
-import scala.tools.testing.ClearAfterClass
-
-object InlineWarningTest extends ClearAfterClass.Clearable {
- val argsNoWarn = "-Yopt:l:classpath"
- val args = argsNoWarn + " -Yopt-warnings"
- var compiler = newCompiler(extraArgs = args)
- var compilerWarnAll = newCompiler(extraArgs = argsNoWarn + " -Yopt-warnings:_")
- def clear(): Unit = { compiler = null; compilerWarnAll = null }
-}
+
+import scala.tools.testing.BytecodeTesting
+import scala.tools.testing.BytecodeTesting._
@RunWith(classOf[JUnit4])
-class InlineWarningTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = InlineWarningTest
+class InlineWarningTest extends BytecodeTesting {
+ def optCp = "-Yopt:l:classpath"
+ override def compilerArgs = s"$optCp -Yopt-warnings"
- val compiler = InlineWarningTest.compiler
- val compilerWarnAll = InlineWarningTest.compilerWarnAll
+ import compiler._
- def compile(scalaCode: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false, compiler: Global = compiler): List[ClassNode] = {
- compileClasses(compiler)(scalaCode, javaCode, allowMessage)
- }
+ val compilerWarnAll = cached("compilerWarnAll", () => newCompiler(extraArgs = s"$optCp -Yopt-warnings:_"))
@Test
def nonFinal(): Unit = {
@@ -66,7 +38,7 @@ class InlineWarningTest extends ClearAfterClass {
"C::m1()I is annotated @inline but cannot be inlined: the method is not final and may be overridden",
"T::m2()I is annotated @inline but cannot be inlined: the method is not final and may be overridden",
"D::m2()I is annotated @inline but cannot be inlined: the method is not final and may be overridden")
- compile(code, allowMessage = i => {count += 1; warns.exists(i.msg contains _)})
+ compileToBytes(code, allowMessage = i => {count += 1; warns.exists(i.msg contains _)})
assert(count == 4, count)
}
@@ -81,7 +53,7 @@ class InlineWarningTest extends ClearAfterClass {
""".stripMargin
var c = 0
- compile(code, allowMessage = i => {c += 1; i.msg contains "operand stack at the callsite in C::t1()V contains more values"})
+ compileToBytes(code, allowMessage = i => {c += 1; i.msg contains "operand stack at the callsite in C::t1()V contains more values"})
assert(c == 1, c)
}
@@ -111,14 +83,14 @@ class InlineWarningTest extends ClearAfterClass {
|Note that the parent class A is defined in a Java source (mixed compilation), no bytecode is available.""".stripMargin)
var c = 0
- val List(b) = compile(scalaCode, List((javaCode, "A.java")), allowMessage = i => {c += 1; warns.tail.exists(i.msg contains _)})
+ val List(b) = compileToBytes(scalaCode, List((javaCode, "A.java")), allowMessage = i => {c += 1; warns.tail.exists(i.msg contains _)})
assert(c == 1, c)
// no warnings here
- compileClasses(newCompiler(extraArgs = InlineWarningTest.argsNoWarn + " -Yopt-warnings:none"))(scalaCode, List((javaCode, "A.java")))
+ newCompiler(extraArgs = s"$optCp -Yopt-warnings:none").compileToBytes(scalaCode, List((javaCode, "A.java")))
c = 0
- compileClasses(newCompiler(extraArgs = InlineWarningTest.argsNoWarn + " -Yopt-warnings:no-inline-mixed"))(scalaCode, List((javaCode, "A.java")), allowMessage = i => {c += 1; warns.exists(i.msg contains _)})
+ newCompiler(extraArgs = s"$optCp -Yopt-warnings:no-inline-mixed").compileToBytes(scalaCode, List((javaCode, "A.java")), allowMessage = i => {c += 1; warns.exists(i.msg contains _)})
assert(c == 2, c)
}
@@ -145,7 +117,7 @@ class InlineWarningTest extends ClearAfterClass {
|that would cause an IllegalAccessError when inlined into class N""".stripMargin
var c = 0
- compile(code, allowMessage = i => { c += 1; i.msg contains warn })
+ compileToBytes(code, allowMessage = i => { c += 1; i.msg contains warn })
assert(c == 1, c)
}
@@ -164,7 +136,7 @@ class InlineWarningTest extends ClearAfterClass {
| def t(a: M) = a.f(x => x + 1)
|}
""".stripMargin
- compile(code, allowMessage = _ => false) // no warnings allowed
+ compileToBytes(code, allowMessage = _ => false) // no warnings allowed
val warn =
"""M::f(Lscala/Function1;)I could not be inlined:
@@ -172,7 +144,7 @@ class InlineWarningTest extends ClearAfterClass {
|that would cause an IllegalAccessError when inlined into class N""".stripMargin
var c = 0
- compile(code, compiler = compilerWarnAll, allowMessage = i => { c += 1; i.msg contains warn })
+ compilerWarnAll.compileToBytes(code, allowMessage = i => { c += 1; i.msg contains warn })
assert(c == 1, c)
}
@@ -193,7 +165,7 @@ class InlineWarningTest extends ClearAfterClass {
|does not have the same strictfp mode as the callee C::f()I.""".stripMargin
var c = 0
- compile(code, allowMessage = i => { c += 1; i.msg contains warn })
+ compileToBytes(code, allowMessage = i => { c += 1; i.msg contains warn })
assert(c == 1, c)
}
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala
index 6460158e71..c2ada8afec 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala
@@ -2,34 +2,22 @@ package scala.tools.nsc
package backend.jvm
package opt
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
-import scala.tools.asm.Opcodes._
-import org.junit.Assert._
-
-import scala.tools.asm.tree._
-import scala.tools.testing.AssertUtil._
-
-import CodeGenTools._
-import scala.tools.partest.ASMConverters
-import ASMConverters._
-import AsmUtils._
import scala.collection.JavaConverters._
-import scala.tools.testing.ClearAfterClass
-
-object InlinerIllegalAccessTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler(extraArgs = "-Yopt:l:none")
- def clear(): Unit = { compiler = null }
-}
+import scala.tools.asm.Opcodes._
+import scala.tools.asm.tree._
+import scala.tools.nsc.backend.jvm.AsmUtils._
+import scala.tools.testing.BytecodeTesting
@RunWith(classOf[JUnit4])
-class InlinerIllegalAccessTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = InlinerIllegalAccessTest
+class InlinerIllegalAccessTest extends BytecodeTesting {
+ override def compilerArgs = "-Yopt:l:none"
- val compiler = InlinerIllegalAccessTest.compiler
- import compiler.genBCode.bTypes._
+ import compiler._
+ import global.genBCode.bTypes._
def addToRepo(cls: List[ClassNode]): Unit = for (c <- cls) byteCodeRepository.add(c, ByteCodeRepository.Classfile)
def assertEmpty(ins: Option[AbstractInsnNode]) = for (i <- ins)
@@ -51,7 +39,7 @@ class InlinerIllegalAccessTest extends ClearAfterClass {
|}
""".stripMargin
- val allClasses = compileClasses(compiler)(code)
+ val allClasses = compileClasses(code)
val List(cClass, dClass, eClass) = allClasses
assert(cClass.name == "a/C" && dClass.name == "a/D" && eClass.name == "b/E", s"${cClass.name}, ${dClass.name}, ${eClass.name}")
addToRepo(allClasses) // they are not on the compiler's classpath, so we add them manually to the code repo
@@ -127,7 +115,7 @@ class InlinerIllegalAccessTest extends ClearAfterClass {
|}
""".stripMargin
- val allClasses = compileClasses(compiler)(code)
+ val allClasses = compileClasses(code)
val List(cCl, dCl, eCl, fCl, gCl, hCl, iCl) = allClasses
addToRepo(allClasses)
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerSeparateCompilationTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerSeparateCompilationTest.scala
index 075513a2b7..b196f1a9ba 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerSeparateCompilationTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerSeparateCompilationTest.scala
@@ -2,26 +2,15 @@ package scala.tools.nsc
package backend.jvm
package opt
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
-import scala.tools.asm.Opcodes._
-import org.junit.Assert._
-import CodeGenTools._
-import scala.tools.partest.ASMConverters
-import ASMConverters._
-import AsmUtils._
-
-import scala.collection.JavaConverters._
-
-object InlinerSeparateCompilationTest {
- val args = "-Yopt:l:classpath"
-}
+import scala.tools.testing.BytecodeTesting._
@RunWith(classOf[JUnit4])
class InlinerSeparateCompilationTest {
- import InlinerSeparateCompilationTest._
+ val args = "-Yopt:l:classpath"
@Test
def inlnieMixedinMember(): Unit = {
@@ -44,9 +33,9 @@ class InlinerSeparateCompilationTest {
val warn = "T::f()I is annotated @inline but cannot be inlined: the method is not final and may be overridden"
val List(c, o, oMod, t) = compileClassesSeparately(List(codeA, codeB), args + " -Yopt-warnings", _.msg contains warn)
- assertInvoke(getSingleMethod(c, "t1"), "T", "f")
- assertNoInvoke(getSingleMethod(c, "t2"))
- assertNoInvoke(getSingleMethod(c, "t3"))
+ assertInvoke(getMethod(c, "t1"), "T", "f")
+ assertNoInvoke(getMethod(c, "t2"))
+ assertNoInvoke(getMethod(c, "t3"))
}
@Test
@@ -64,7 +53,7 @@ class InlinerSeparateCompilationTest {
""".stripMargin
val List(c, t) = compileClassesSeparately(List(codeA, codeB), args)
- assertNoInvoke(getSingleMethod(c, "t1"))
+ assertNoInvoke(getMethod(c, "t1"))
}
@Test
@@ -87,7 +76,7 @@ class InlinerSeparateCompilationTest {
""".stripMargin
val List(c, t, u) = compileClassesSeparately(List(codeA, codeB), args)
- for (m <- List("t1", "t2", "t3")) assertNoInvoke(getSingleMethod(c, m))
+ for (m <- List("t1", "t2", "t3")) assertNoInvoke(getMethod(c, m))
}
@Test
@@ -108,7 +97,7 @@ class InlinerSeparateCompilationTest {
""".stripMargin
val List(a, t) = compileClassesSeparately(List(codeA, assembly), args)
- assertNoInvoke(getSingleMethod(t, "f"))
- assertNoInvoke(getSingleMethod(a, "n"))
+ assertNoInvoke(getMethod(t, "f"))
+ assertNoInvoke(getMethod(a, "n"))
}
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
index e2a495fb2b..fd020c7d93 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
@@ -2,56 +2,44 @@ package scala.tools.nsc
package backend.jvm
package opt
+import org.junit.Assert._
+import org.junit.{Ignore, Test}
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
+
+import scala.collection.JavaConverters._
import scala.collection.generic.Clearable
import scala.tools.asm.Opcodes._
-import org.junit.Assert._
-
import scala.tools.asm.tree._
+import scala.tools.nsc.backend.jvm.BackendReporting._
import scala.tools.nsc.reporters.StoreReporter
+import scala.tools.partest.ASMConverters._
+import scala.tools.testing.BytecodeTesting
+import scala.tools.testing.BytecodeTesting._
-import CodeGenTools._
-import scala.tools.partest.ASMConverters
-import ASMConverters._
-import AsmUtils._
-
-import BackendReporting._
-
-import scala.collection.JavaConverters._
-import scala.tools.testing.ClearAfterClass
+@RunWith(classOf[JUnit4])
+class InlinerTest extends BytecodeTesting {
+ override def compilerArgs = "-Yopt:l:classpath -Yopt-warnings"
-object InlinerTest extends ClearAfterClass.Clearable {
- val args = "-Yopt:l:classpath -Yopt-warnings"
- var compiler = newCompiler(extraArgs = args)
- var inlineOnlyCompiler = newCompiler(extraArgs = "-Yopt:inline-project")
+ val inlineOnlyCompiler = cached("inlineOnlyCompiler", () => newCompiler(extraArgs = "-Yopt:inline-project"))
+ import compiler._
+ import global.genBCode.bTypes
// allows inspecting the caches after a compilation run
def notPerRun: List[Clearable] = List(
- compiler.genBCode.bTypes.classBTypeFromInternalName,
- compiler.genBCode.bTypes.byteCodeRepository.compilingClasses,
- compiler.genBCode.bTypes.byteCodeRepository.parsedClasses,
- compiler.genBCode.bTypes.callGraph.callsites)
- notPerRun foreach compiler.perRunCaches.unrecordCache
-
- def clear(): Unit = { compiler = null; inlineOnlyCompiler = null }
-}
+ bTypes.classBTypeFromInternalName,
+ bTypes.byteCodeRepository.compilingClasses,
+ bTypes.byteCodeRepository.parsedClasses,
+ bTypes.callGraph.callsites)
+ notPerRun foreach global.perRunCaches.unrecordCache
-@RunWith(classOf[JUnit4])
-class InlinerTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = InlinerTest
-
- val compiler = InlinerTest.compiler
- import compiler.genBCode.bTypes._
- import compiler.genBCode.bTypes.backendUtils._
+ import global.genBCode.bTypes.{byteCodeRepository, callGraph, inliner, inlinerHeuristics}
import inlinerHeuristics._
- val inlineOnlyCompiler = InlinerTest.inlineOnlyCompiler
def compile(scalaCode: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): List[ClassNode] = {
- InlinerTest.notPerRun.foreach(_.clear())
- compileClasses(compiler)(scalaCode, javaCode, allowMessage)
+ notPerRun.foreach(_.clear())
+ compileToBytes(scalaCode, javaCode, allowMessage)
// Use the class nodes stored in the byteCodeRepository. The ones returned by compileClasses are not the same,
// these are created new from the classfile byte array. They are completely separate instances which cannot
// be used to look up methods / callsites in the callGraph hash maps for example.
@@ -72,7 +60,7 @@ class InlinerTest extends ClearAfterClass {
def gMethAndFCallsite(code: String, mod: ClassNode => Unit = _ => ()) = {
val List(c) = compile(code)
mod(c)
- val gMethod = findAsmMethod(c, "g")
+ val gMethod = getAsmMethod(c, "g")
val fCall = getCallsite(gMethod, "f")
(gMethod, fCall)
}
@@ -146,7 +134,7 @@ class InlinerTest extends ClearAfterClass {
assertSameCode(convertMethod(g), gBeforeLocalOpt)
- compiler.genBCode.bTypes.localOpt.methodOptimizations(g, "C")
+ global.genBCode.bTypes.localOpt.methodOptimizations(g, "C")
assertSameCode(convertMethod(g), invokeQQQ :+ Op(ATHROW))
}
@@ -160,7 +148,7 @@ class InlinerTest extends ClearAfterClass {
""".stripMargin
val can = canInlineTest(code, cls => {
- val f = cls.methods.asScala.find(_.name == "f").get
+ val f = getAsmMethod(cls, "f")
f.access |= ACC_SYNCHRONIZED
})
assert(can.nonEmpty && can.get.isInstanceOf[SynchronizedMethod], can)
@@ -209,7 +197,7 @@ class InlinerTest extends ClearAfterClass {
""".stripMargin
val List(c, d) = compile(code)
- val hMeth = findAsmMethod(d, "h")
+ val hMeth = getAsmMethod(d, "h")
val gCall = getCallsite(hMeth, "g")
val r = inliner.canInlineBody(gCall)
assert(r.nonEmpty && r.get.isInstanceOf[IllegalAccessInstruction], r)
@@ -226,7 +214,7 @@ class InlinerTest extends ClearAfterClass {
|}
""".stripMargin
val List(cCls) = compile(code)
- val instructions = getSingleMethod(cCls, "test").instructions
+ val instructions = getInstructions(cCls, "test")
assert(instructions.contains(Op(ICONST_0)), instructions.stringLines)
assert(!instructions.contains(Op(ICONST_1)), instructions)
}
@@ -292,7 +280,7 @@ class InlinerTest extends ClearAfterClass {
|}
""".stripMargin
val List(c, _, _) = compile(code)
- val ins = getSingleMethod(c, "f").instructions
+ val ins = getInstructions(c, "f")
val invokeSysArraycopy = Invoke(INVOKESTATIC, "java/lang/System", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V", false)
assert(ins contains invokeSysArraycopy, ins.stringLines)
}
@@ -324,7 +312,7 @@ class InlinerTest extends ClearAfterClass {
|}
""".stripMargin
val List(c, t) = compile(code)
- assertNoInvoke(getSingleMethod(c, "g"))
+ assertNoInvoke(getMethod(c, "g"))
}
@Test
@@ -337,7 +325,7 @@ class InlinerTest extends ClearAfterClass {
""".stripMargin
val List(c) = compile(code)
// no more invoke, f is inlined
- assertNoInvoke(getSingleMethod(c, "g"))
+ assertNoInvoke(getMethod(c, "g"))
}
@Test
@@ -349,7 +337,7 @@ class InlinerTest extends ClearAfterClass {
""".stripMargin
val List(c) = compile(code)
- val fMeth = findAsmMethod(c, "f")
+ val fMeth = getAsmMethod(c, "f")
val call = getCallsite(fMeth, "lowestOneBit")
val warning = inliner.canInlineBody(call)
@@ -388,7 +376,7 @@ class InlinerTest extends ClearAfterClass {
""".stripMargin
// use a compiler without local optimizations (cleanups)
- val List(c) = compileClasses(inlineOnlyCompiler)(code)
+ val c = inlineOnlyCompiler.compileClass(code)
val ms @ List(f1, f2, g1, g2) = c.methods.asScala.filter(_.name.length == 2).toList
// stack height at callsite of f1 is 1, so max of g1 after inlining is max of f1 + 1
@@ -433,7 +421,7 @@ class InlinerTest extends ClearAfterClass {
var c = 0
val List(b) = compile(scalaCode, List((javaCode, "A.java")), allowMessage = i => {c += 1; i.msg contains warn})
assert(c == 1, c)
- val ins = getSingleMethod(b, "g").instructions
+ val ins = getInstructions(b, "g")
val invokeFlop = Invoke(INVOKEVIRTUAL, "B", "flop", "()I", false)
assert(ins contains invokeFlop, ins.stringLines)
}
@@ -453,8 +441,8 @@ class InlinerTest extends ClearAfterClass {
""".stripMargin
val List(c, t) = compile(code)
// both are just `return 1`, no more calls
- assertNoInvoke(getSingleMethod(c, "t1"))
- assertNoInvoke(getSingleMethod(c, "t2"))
+ assertNoInvoke(getMethod(c, "t1"))
+ assertNoInvoke(getMethod(c, "t2"))
}
@Test
@@ -472,8 +460,8 @@ class InlinerTest extends ClearAfterClass {
|}
""".stripMargin
val List(c, t, u) = compile(code)
- assertNoInvoke(getSingleMethod(c, "t1"))
- assertNoInvoke(getSingleMethod(c, "t2"))
+ assertNoInvoke(getMethod(c, "t1"))
+ assertNoInvoke(getMethod(c, "t2"))
}
@Test
@@ -493,8 +481,8 @@ class InlinerTest extends ClearAfterClass {
var count = 0
val List(c, t) = compile(code, allowMessage = i => {count += 1; warns.exists(i.msg contains _)})
assert(count == 2, count)
- assertInvoke(getSingleMethod(c, "t1"), "T", "f")
- assertInvoke(getSingleMethod(c, "t2"), "C", "f")
+ assertInvoke(getMethod(c, "t1"), "T", "f")
+ assertInvoke(getMethod(c, "t2"), "C", "f")
}
@Test
@@ -508,7 +496,7 @@ class InlinerTest extends ClearAfterClass {
|}
""".stripMargin
val List(c, t) = compile(code)
- assertNoInvoke(getSingleMethod(c, "t1"))
+ assertNoInvoke(getMethod(c, "t1"))
}
@Test
@@ -532,11 +520,11 @@ class InlinerTest extends ClearAfterClass {
val List(c, oMirror, oModule, t) = compile(code, allowMessage = i => {count += 1; i.msg contains warn})
assert(count == 1, count)
- assertNoInvoke(getSingleMethod(t, "f"))
+ assertNoInvoke(getMethod(t, "f"))
- assertNoInvoke(getSingleMethod(c, "t1"))
- assertNoInvoke(getSingleMethod(c, "t2"))
- assertInvoke(getSingleMethod(c, "t3"), "T", "f")
+ assertNoInvoke(getMethod(c, "t1"))
+ assertNoInvoke(getMethod(c, "t2"))
+ assertInvoke(getMethod(c, "t3"), "T", "f")
}
@Test
@@ -558,12 +546,12 @@ class InlinerTest extends ClearAfterClass {
val List(assembly, c, t) = compile(code)
- assertNoInvoke(getSingleMethod(t, "f"))
+ assertNoInvoke(getMethod(t, "f"))
- assertNoInvoke(getSingleMethod(assembly, "n"))
+ assertNoInvoke(getMethod(assembly, "n"))
- assertNoInvoke(getSingleMethod(c, "t1"))
- assertNoInvoke(getSingleMethod(c, "t2"))
+ assertNoInvoke(getMethod(c, "t1"))
+ assertNoInvoke(getMethod(c, "t2"))
}
@Test
@@ -636,20 +624,20 @@ class InlinerTest extends ClearAfterClass {
val List(ca, cb, t1, t2a, t2b) = compile(code, allowMessage = i => {count += 1; i.msg contains warning})
assert(count == 4, count) // see comments, f is not inlined 4 times
- assertNoInvoke(getSingleMethod(t2a, "g2a"))
- assertInvoke(getSingleMethod(t2b, "g2b"), "T1", "f")
+ assertNoInvoke(getMethod(t2a, "g2a"))
+ assertInvoke(getMethod(t2b, "g2b"), "T1", "f")
- assertInvoke(getSingleMethod(ca, "m1a"), "T1", "f")
- assertNoInvoke(getSingleMethod(ca, "m2a")) // no invoke, see comment on def g2a
- assertNoInvoke(getSingleMethod(ca, "m3a"))
- assertInvoke(getSingleMethod(ca, "m4a"), "T1", "f")
- assertNoInvoke(getSingleMethod(ca, "m5a"))
+ assertInvoke(getMethod(ca, "m1a"), "T1", "f")
+ assertNoInvoke(getMethod(ca, "m2a")) // no invoke, see comment on def g2a
+ assertNoInvoke(getMethod(ca, "m3a"))
+ assertInvoke(getMethod(ca, "m4a"), "T1", "f")
+ assertNoInvoke(getMethod(ca, "m5a"))
- assertInvoke(getSingleMethod(cb, "m1b"), "T1", "f")
- assertInvoke(getSingleMethod(cb, "m2b"), "T1", "f") // invoke, see comment on def g2b
- assertNoInvoke(getSingleMethod(cb, "m3b"))
- assertInvoke(getSingleMethod(cb, "m4b"), "T1", "f")
- assertNoInvoke(getSingleMethod(cb, "m5b"))
+ assertInvoke(getMethod(cb, "m1b"), "T1", "f")
+ assertInvoke(getMethod(cb, "m2b"), "T1", "f") // invoke, see comment on def g2b
+ assertNoInvoke(getMethod(cb, "m3b"))
+ assertInvoke(getMethod(cb, "m4b"), "T1", "f")
+ assertNoInvoke(getMethod(cb, "m5b"))
}
@Test
@@ -666,7 +654,7 @@ class InlinerTest extends ClearAfterClass {
|} // so d.f can be resolved statically. same for E.f
""".stripMargin
val List(c, d, e, eModule, t) = compile(code)
- assertNoInvoke(getSingleMethod(t, "t1"))
+ assertNoInvoke(getMethod(t, "t1"))
}
@Test
@@ -681,8 +669,8 @@ class InlinerTest extends ClearAfterClass {
|}
""".stripMargin
val List(c, d, t) = compile(code)
- assertNoInvoke(getSingleMethod(d, "m"))
- assertNoInvoke(getSingleMethod(c, "m"))
+ assertNoInvoke(getMethod(d, "m"))
+ assertNoInvoke(getMethod(c, "m"))
}
@Test
@@ -696,8 +684,8 @@ class InlinerTest extends ClearAfterClass {
|}
""".stripMargin
val List(c, t) = compile(code)
- val t1 = getSingleMethod(t, "t1")
- val t2 = getSingleMethod(t, "t2")
+ val t1 = getMethod(t, "t1")
+ val t2 = getMethod(t, "t2")
val cast = TypeOp(CHECKCAST, "C")
Set(t1, t2).foreach(m => assert(m.instructions.contains(cast), m.instructions))
}
@@ -777,27 +765,27 @@ class InlinerTest extends ClearAfterClass {
""".stripMargin
val List(c, t, u) = compile(code, allowMessage = _.msg contains "i()I is annotated @inline but cannot be inlined")
- val m1 = getSingleMethod(c, "m1")
+ val m1 = getMethod(c, "m1")
assertInvoke(m1, "T", "a")
assertInvoke(m1, "T", "b")
assertInvoke(m1, "T", "c")
- assertNoInvoke(getSingleMethod(c, "m2"))
+ assertNoInvoke(getMethod(c, "m2"))
- val m3 = getSingleMethod(c, "m3")
+ val m3 = getMethod(c, "m3")
assertInvoke(m3, "T", "f")
assertInvoke(m3, "T", "g")
assertInvoke(m3, "T", "h")
assertInvoke(m3, "T", "i")
- val m4 = getSingleMethod(c, "m4")
+ val m4 = getMethod(c, "m4")
assertInvoke(m4, "U", "a")
assertInvoke(m4, "U", "b")
assertInvoke(m4, "U", "c")
- assertNoInvoke(getSingleMethod(c, "m5"))
+ assertNoInvoke(getMethod(c, "m5"))
- val m6 = getSingleMethod(c, "m6")
+ val m6 = getMethod(c, "m6")
assertInvoke(m6, "U", "f")
assertInvoke(m6, "U", "g")
assertInvoke(m6, "U", "h")
@@ -837,7 +825,7 @@ class InlinerTest extends ClearAfterClass {
var c = 0
- compileClasses(newCompiler(extraArgs = InlinerTest.args + " -Yopt-warnings:_"))(
+ newCompiler(extraArgs = compilerArgs + " -Yopt-warnings:_").compileClasses(
scalaCode,
List((javaCode, "A.java")),
allowMessage = i => {c += 1; i.msg contains warn})
@@ -881,15 +869,15 @@ class InlinerTest extends ClearAfterClass {
val List(a, b, t) = compile(code, allowMessage = i => {c += 1; i.msg contains warn})
assert(c == 1, c)
- assertInvoke(getSingleMethod(b, "t1"), "Aa", "f1")
- assertInvoke(getSingleMethod(b, "t2"), "B", "B$$f2m")
- assertInvoke(getSingleMethod(b, "t3"), "B", "<init>")
- assertInvoke(getSingleMethod(b, "t4"), "B", "<init>")
+ assertInvoke(getMethod(b, "t1"), "Aa", "f1")
+ assertInvoke(getMethod(b, "t2"), "B", "B$$f2m")
+ assertInvoke(getMethod(b, "t3"), "B", "<init>")
+ assertInvoke(getMethod(b, "t4"), "B", "<init>")
- assertInvoke(getSingleMethod(t, "t1"), "B", "f1")
- assertInvoke(getSingleMethod(t, "t2"), "B", "B$$f2m")
- assertInvoke(getSingleMethod(t, "t3"), "B", "<init>")
- assertInvoke(getSingleMethod(t, "t4"), "B", "<init>")
+ assertInvoke(getMethod(t, "t1"), "B", "f1")
+ assertInvoke(getMethod(t, "t2"), "B", "B$$f2m")
+ assertInvoke(getMethod(t, "t3"), "B", "<init>")
+ assertInvoke(getMethod(t, "t4"), "B", "<init>")
}
@Test
@@ -899,8 +887,8 @@ class InlinerTest extends ClearAfterClass {
| def t = System.arraycopy(null, 0, null, 0, 0)
|}
""".stripMargin
- val List(c) = compileClasses(newCompiler(extraArgs = InlinerTest.args + " -Yopt-inline-heuristics:everything"))(code)
- assertInvoke(getSingleMethod(c, "t"), "java/lang/System", "arraycopy")
+ val c = newCompiler(extraArgs = compilerArgs + " -Yopt-inline-heuristics:everything").compileClass(code)
+ assertInvoke(getMethod(c, "t"), "java/lang/System", "arraycopy")
}
@Test
@@ -914,7 +902,7 @@ class InlinerTest extends ClearAfterClass {
""".stripMargin
val List(c) = compile(code)
- assertInvoke(getSingleMethod(c, "t"), "java/lang/Error", "<init>")
+ assertInvoke(getMethod(c, "t"), "java/lang/Error", "<init>")
}
@Test
@@ -927,7 +915,7 @@ class InlinerTest extends ClearAfterClass {
""".stripMargin
val List(c) = compile(code)
- val t = getSingleMethod(c, "t").instructions
+ val t = getInstructions(c, "t")
assertNoInvoke(t)
assert(1 == t.collect({case Ldc(_, "hai!") => }).size) // push-pop eliminates the first LDC("hai!")
assert(1 == t.collect({case Jump(IFNONNULL, _) => }).size) // one single null check
@@ -954,12 +942,12 @@ class InlinerTest extends ClearAfterClass {
val List(c, _, _) = compile(code)
- val t1 = getSingleMethod(c, "t1")
+ val t1 = getMethod(c, "t1")
assertNoIndy(t1)
// the indy call is inlined into t, and the closure elimination rewrites the closure invocation to the body method
assertInvoke(t1, "C", "C$$$anonfun$2")
- val t2 = getSingleMethod(c, "t2")
+ val t2 = getMethod(c, "t2")
assertNoIndy(t2)
assertInvoke(t2, "M$", "M$$$anonfun$1")
}
@@ -976,9 +964,9 @@ class InlinerTest extends ClearAfterClass {
""".stripMargin
val List(c) = compile(code)
- val hMeth = findAsmMethod(c, "h")
- val gMeth = findAsmMethod(c, "g")
- val iMeth = findAsmMethod(c, "i")
+ val hMeth = getAsmMethod(c, "h")
+ val gMeth = getAsmMethod(c, "g")
+ val iMeth = getAsmMethod(c, "i")
val fCall = getCallsite(gMeth, "f")
val gCall = getCallsite(hMeth, "g")
val hCall = getCallsite(iMeth, "h")
@@ -1005,7 +993,7 @@ class InlinerTest extends ClearAfterClass {
""".stripMargin
val List(cl) = compile(code)
- val List(b, c, d) = List("b", "c", "d").map(findAsmMethod(cl, _))
+ val List(b, c, d) = List("b", "c", "d").map(getAsmMethod(cl, _))
val aCall = getCallsite(b, "a")
val bCall = getCallsite(c, "b")
val cCall = getCallsite(d, "c")
@@ -1045,15 +1033,15 @@ class InlinerTest extends ClearAfterClass {
""".stripMargin
val List(c) = compile(code)
- assertInvoke(getSingleMethod(c, "t1"), "C", "C$$$anonfun$1")
- assertInvoke(getSingleMethod(c, "t2"), "C", "a")
- assertInvoke(getSingleMethod(c, "t3"), "C", "b")
- assertNoInvoke(getSingleMethod(c, "t4"))
- assertNoInvoke(getSingleMethod(c, "t5"))
- assertNoInvoke(getSingleMethod(c, "t6"))
- assertInvoke(getSingleMethod(c, "t7"), "C", "c")
- assertInvoke(getSingleMethod(c, "t8"), "scala/Predef$", "println")
- assertNoInvoke(getSingleMethod(c, "t9"))
+ assertInvoke(getMethod(c, "t1"), "C", "C$$$anonfun$1")
+ assertInvoke(getMethod(c, "t2"), "C", "a")
+ assertInvoke(getMethod(c, "t3"), "C", "b")
+ assertNoInvoke(getMethod(c, "t4"))
+ assertNoInvoke(getMethod(c, "t5"))
+ assertNoInvoke(getMethod(c, "t6"))
+ assertInvoke(getMethod(c, "t7"), "C", "c")
+ assertInvoke(getMethod(c, "t8"), "scala/Predef$", "println")
+ assertNoInvoke(getMethod(c, "t9"))
}
@Test
@@ -1078,15 +1066,15 @@ class InlinerTest extends ClearAfterClass {
""".stripMargin
val List(c) = compile(code)
- assertNoInvoke(getSingleMethod(c, "t1"))
- assertInvoke(getSingleMethod(c, "t2"), "C", "f2")
- assertInvoke(getSingleMethod(c, "t3"), "C", "f1")
- assertInvoke(getSingleMethod(c, "t4"), "C", "f2")
- assertNoInvoke(getSingleMethod(c, "t5"))
- assertInvoke(getSingleMethod(c, "t6"), "C", "f3")
- assertNoInvoke(getSingleMethod(c, "t7"))
- assertInvoke(getSingleMethod(c, "t8"), "C", "f1")
- assertNoInvoke(getSingleMethod(c, "t9"))
+ assertNoInvoke(getMethod(c, "t1"))
+ assertInvoke(getMethod(c, "t2"), "C", "f2")
+ assertInvoke(getMethod(c, "t3"), "C", "f1")
+ assertInvoke(getMethod(c, "t4"), "C", "f2")
+ assertNoInvoke(getMethod(c, "t5"))
+ assertInvoke(getMethod(c, "t6"), "C", "f3")
+ assertNoInvoke(getMethod(c, "t7"))
+ assertInvoke(getMethod(c, "t8"), "C", "f1")
+ assertNoInvoke(getMethod(c, "t9"))
}
@Test
@@ -1109,11 +1097,11 @@ class InlinerTest extends ClearAfterClass {
""".stripMargin
val List(c) = compile(code)
- assertInvoke(getSingleMethod(c, "t1"), "C", "C$$$anonfun$1")
- assertInvoke(getSingleMethod(c, "t2"), "C", "C$$$anonfun$2")
- assertInvoke(getSingleMethod(c, "t3"), "scala/Function1", "apply$mcII$sp")
- assertInvoke(getSingleMethod(c, "t4"), "scala/Function1", "apply$mcII$sp")
- assertInvoke(getSingleMethod(c, "t5"), "C", "h")
+ assertInvoke(getMethod(c, "t1"), "C", "C$$$anonfun$1")
+ assertInvoke(getMethod(c, "t2"), "C", "C$$$anonfun$2")
+ assertInvoke(getMethod(c, "t3"), "scala/Function1", "apply$mcII$sp")
+ assertInvoke(getMethod(c, "t4"), "scala/Function1", "apply$mcII$sp")
+ assertInvoke(getMethod(c, "t5"), "C", "h")
}
@Test
@@ -1133,7 +1121,7 @@ class InlinerTest extends ClearAfterClass {
|when entering an exception handler declared in the inlined method.""".stripMargin
val List(c) = compile(code, allowMessage = _.msg contains warn)
- assertInvoke(getSingleMethod(c, "t"), "C", "g")
+ assertInvoke(getMethod(c, "t"), "C", "g")
}
@Test
@@ -1157,8 +1145,8 @@ class InlinerTest extends ClearAfterClass {
|that would cause an IllegalAccessError when inlined into class D.""".stripMargin
val List(c, d) = compile(code, allowMessage = _.msg contains warn)
- assertInvoke(getSingleMethod(c, "h"), "C", "f$1")
- assertInvoke(getSingleMethod(d, "t"), "C", "h")
+ assertInvoke(getMethod(c, "h"), "C", "f$1")
+ assertInvoke(getMethod(d, "t"), "C", "h")
}
@Test
@@ -1176,8 +1164,8 @@ class InlinerTest extends ClearAfterClass {
""".stripMargin
val List(c, d) = compile(code)
- assertNoInvoke(getSingleMethod(c, "g"))
- assertNoInvoke(getSingleMethod(d, "t"))
+ assertNoInvoke(getMethod(c, "g"))
+ assertNoInvoke(getMethod(d, "t"))
}
@Test
@@ -1285,40 +1273,40 @@ class InlinerTest extends ClearAfterClass {
""".stripMargin
val List(c, _, _) = compile(code)
- assertSameSummary(getSingleMethod(c, "t1"), List(BIPUSH, "C$$$anonfun$1", IRETURN))
- assertSameSummary(getSingleMethod(c, "t1a"), List(LCONST_1, "C$$$anonfun$2", IRETURN))
- assertSameSummary(getSingleMethod(c, "t2"), List(ICONST_1, ICONST_2, "C$$$anonfun$3",IRETURN))
+ assertSameSummary(getMethod(c, "t1"), List(BIPUSH, "C$$$anonfun$1", IRETURN))
+ assertSameSummary(getMethod(c, "t1a"), List(LCONST_1, "C$$$anonfun$2", IRETURN))
+ assertSameSummary(getMethod(c, "t2"), List(ICONST_1, ICONST_2, "C$$$anonfun$3",IRETURN))
// val a = new ValKl(n); new ValKl(anonfun(a.x)).x
// value class instantiation-extraction should be optimized by boxing elim
- assertSameSummary(getSingleMethod(c, "t3"), List(
+ assertSameSummary(getMethod(c, "t3"), List(
NEW, DUP, ICONST_1, "<init>", ASTORE,
NEW, DUP, ALOAD, "x",
"C$$$anonfun$4",
"<init>",
"x", IRETURN))
- assertSameSummary(getSingleMethod(c, "t4"), List(BIPUSH, "C$$$anonfun$5", "boxToInteger", ARETURN))
- assertSameSummary(getSingleMethod(c, "t4a"), List(ICONST_1, LDC, "C$$$anonfun$6", LRETURN))
- assertSameSummary(getSingleMethod(c, "t5"), List(BIPUSH, ICONST_3, "C$$$anonfun$7", "boxToInteger", ARETURN))
- assertSameSummary(getSingleMethod(c, "t5a"), List(BIPUSH, BIPUSH, I2B, "C$$$anonfun$8", IRETURN))
- assertSameSummary(getSingleMethod(c, "t6"), List(BIPUSH, "C$$$anonfun$9", RETURN))
- assertSameSummary(getSingleMethod(c, "t7"), List(ICONST_1, "C$$$anonfun$10", RETURN))
- assertSameSummary(getSingleMethod(c, "t8"), List(ICONST_1, LDC, "C$$$anonfun$11", LRETURN))
- assertSameSummary(getSingleMethod(c, "t9"), List(ICONST_1, "boxToInteger", "C$$$anonfun$12", RETURN))
+ assertSameSummary(getMethod(c, "t4"), List(BIPUSH, "C$$$anonfun$5", "boxToInteger", ARETURN))
+ assertSameSummary(getMethod(c, "t4a"), List(ICONST_1, LDC, "C$$$anonfun$6", LRETURN))
+ assertSameSummary(getMethod(c, "t5"), List(BIPUSH, ICONST_3, "C$$$anonfun$7", "boxToInteger", ARETURN))
+ assertSameSummary(getMethod(c, "t5a"), List(BIPUSH, BIPUSH, I2B, "C$$$anonfun$8", IRETURN))
+ assertSameSummary(getMethod(c, "t6"), List(BIPUSH, "C$$$anonfun$9", RETURN))
+ assertSameSummary(getMethod(c, "t7"), List(ICONST_1, "C$$$anonfun$10", RETURN))
+ assertSameSummary(getMethod(c, "t8"), List(ICONST_1, LDC, "C$$$anonfun$11", LRETURN))
+ assertSameSummary(getMethod(c, "t9"), List(ICONST_1, "boxToInteger", "C$$$anonfun$12", RETURN))
// t9a inlines Range.foreach, which is quite a bit of code, so just testing the core
- assertInvoke(getSingleMethod(c, "t9a"), "C", "C$$$anonfun$13")
- assertInvoke(getSingleMethod(c, "t9a"), "scala/runtime/BoxesRunTime", "boxToInteger")
+ assertInvoke(getMethod(c, "t9a"), "C", "C$$$anonfun$13")
+ assertInvoke(getMethod(c, "t9a"), "scala/runtime/BoxesRunTime", "boxToInteger")
- assertSameSummary(getSingleMethod(c, "t10"), List(
+ assertSameSummary(getMethod(c, "t10"), List(
ICONST_1, ISTORE,
ALOAD, ILOAD,
"C$$$anonfun$14", RETURN))
// t10a inlines Range.foreach
- assertInvoke(getSingleMethod(c, "t10a"), "C", "C$$$anonfun$15")
- assertDoesNotInvoke(getSingleMethod(c, "t10a"), "boxToInteger")
+ assertInvoke(getMethod(c, "t10a"), "C", "C$$$anonfun$15")
+ assertDoesNotInvoke(getMethod(c, "t10a"), "boxToInteger")
}
@Test
@@ -1341,8 +1329,8 @@ class InlinerTest extends ClearAfterClass {
|}
""".stripMargin
val List(c) = compile(code)
- assertSameCode(getSingleMethod(c, "t1"), List(Op(ICONST_0), Op(ICONST_1), Op(IADD), Op(IRETURN)))
- assertEquals(getSingleMethod(c, "t2").instructions collect { case i: Invoke => i.owner +"."+ i.name }, List(
+ assertSameCode(getMethod(c, "t1"), List(Op(ICONST_0), Op(ICONST_1), Op(IADD), Op(IRETURN)))
+ assertEquals(getInstructions(c, "t2") collect { case i: Invoke => i.owner +"."+ i.name }, List(
"scala/runtime/IntRef.create", "C.C$$$anonfun$1"))
}
@@ -1382,11 +1370,11 @@ class InlinerTest extends ClearAfterClass {
|}
""".stripMargin
val List(c) = compile(code)
- assertSameCode(getSingleMethod(c, "t1"), List(Op(ICONST_3), Op(ICONST_4), Op(IADD), Op(IRETURN)))
- assertSameCode(getSingleMethod(c, "t2"), List(Op(ICONST_1), Op(ICONST_2), Op(IADD), Op(IRETURN)))
- assertSameCode(getSingleMethod(c, "t3"), List(Op(ICONST_1), Op(ICONST_3), Op(ISUB), Op(IRETURN)))
- assertNoInvoke(getSingleMethod(c, "t4"))
- assertNoInvoke(getSingleMethod(c, "t5"))
+ assertSameCode(getMethod(c, "t1"), List(Op(ICONST_3), Op(ICONST_4), Op(IADD), Op(IRETURN)))
+ assertSameCode(getMethod(c, "t2"), List(Op(ICONST_1), Op(ICONST_2), Op(IADD), Op(IRETURN)))
+ assertSameCode(getMethod(c, "t3"), List(Op(ICONST_1), Op(ICONST_3), Op(ISUB), Op(IRETURN)))
+ assertNoInvoke(getMethod(c, "t4"))
+ assertNoInvoke(getMethod(c, "t5"))
}
@Test
@@ -1412,10 +1400,10 @@ class InlinerTest extends ClearAfterClass {
|class D extends C
""".stripMargin
val List(c, _) = compile(code)
- def casts(m: String) = getSingleMethod(c, m).instructions collect { case TypeOp(CHECKCAST, tp) => tp }
- assertSameCode(getSingleMethod(c, "t1"), List(VarOp(ALOAD, 1), Op(ARETURN)))
- assertSameCode(getSingleMethod(c, "t2"), List(VarOp(ALOAD, 1), Op(ARETURN)))
- assertSameCode(getSingleMethod(c, "t3"), List(VarOp(ALOAD, 1), TypeOp(CHECKCAST, "C"), Op(ARETURN)))
+ def casts(m: String) = getInstructions(c, m) collect { case TypeOp(CHECKCAST, tp) => tp }
+ assertSameCode(getMethod(c, "t1"), List(VarOp(ALOAD, 1), Op(ARETURN)))
+ assertSameCode(getMethod(c, "t2"), List(VarOp(ALOAD, 1), Op(ARETURN)))
+ assertSameCode(getMethod(c, "t3"), List(VarOp(ALOAD, 1), TypeOp(CHECKCAST, "C"), Op(ARETURN)))
assertEquals(casts("t4"), List("C"))
assertEquals(casts("t5"), Nil)
assertEquals(casts("t6"), Nil)
@@ -1440,8 +1428,8 @@ class InlinerTest extends ClearAfterClass {
""".stripMargin
val cls = compile(code)
- val test = cls.find(_.name == "Test$").get
- assertSameSummary(getSingleMethod(test, "f"), List(
+ val test = findClass(cls, "Test$")
+ assertSameSummary(getMethod(test, "f"), List(
GETSTATIC, "mkFoo",
BIPUSH, ISTORE,
IFNONNULL, ACONST_NULL, ATHROW, -1 /*label*/,
@@ -1460,7 +1448,7 @@ class InlinerTest extends ClearAfterClass {
val List(c) = compile(code)
// box-unbox will clean it up
- assertSameSummary(getSingleMethod(c, "t"), List(
+ assertSameSummary(getMethod(c, "t"), List(
ALOAD, "C$$$anonfun$1", IFEQ /*A*/,
"C$$$anonfun$2", IRETURN,
-1 /*A*/, "C$$$anonfun$3", IRETURN))
@@ -1472,7 +1460,7 @@ class InlinerTest extends ClearAfterClass {
val codeB = "class B { def t(a: A) = a.f }"
// tests that no warning is emitted
val List(a, b) = compileClassesSeparately(List(codeA, codeB), extraArgs = "-Yopt:l:project -Yopt-warnings")
- assertInvoke(getSingleMethod(b, "t"), "A", "f")
+ assertInvoke(getMethod(b, "t"), "A", "f")
}
@Test
@@ -1484,7 +1472,7 @@ class InlinerTest extends ClearAfterClass {
""".stripMargin
val List(c, t1, t2) = compile(code, allowMessage = _ => true)
// the forwarder C.f is inlined, so there's no invocation
- assertSameSummary(getSingleMethod(c, "f"), List(ICONST_1, IRETURN))
+ assertSameSummary(getMethod(c, "f"), List(ICONST_1, IRETURN))
}
@Test
@@ -1497,10 +1485,12 @@ class InlinerTest extends ClearAfterClass {
|class C { def t = (new K).f }
""".stripMargin
val c :: _ = compile(code)
- assertSameSummary(getSingleMethod(c, "t"), List(NEW, "<init>", ICONST_1, IRETURN)) // ICONST_1, U.f is inlined (not T.f)
+ assertSameSummary(getMethod(c, "t"), List(NEW, "<init>", ICONST_1, IRETURN)) // ICONST_1, U.f is inlined (not T.f)
}
- @Test
+ // Can be enabled when using 2.12.0-M5 as starr. This test works under a full boostrap, but not
+ // when compiled with M4.
+ @Test @Ignore
def inlineArrayForeach(): Unit = {
val code =
"""class C {
@@ -1509,8 +1499,31 @@ class InlinerTest extends ClearAfterClass {
|}
""".stripMargin
val List(c) = compile(code)
- val t = getSingleMethod(c, "t")
+ val t = getMethod(c, "t")
assertNoIndy(t)
assertInvoke(t, "C", "C$$$anonfun$1")
}
+
+ @Test
+ def t9121(): Unit = {
+ val codes = List(
+ """package p1
+ |object Implicits {
+ | class ScalaObservable(val underlying: Any) extends AnyVal {
+ | @inline def scMap[R](f: String): Any = f.toRx
+ | }
+ | implicit class RichFunction1[T1, R](val f: String) extends AnyVal {
+ | def toRx: Any = ""
+ | }
+ |}
+ """.stripMargin,
+ """
+ |import p1.Implicits._
+ |class C {
+ | def t(): Unit = new ScalaObservable("").scMap("")
+ |}
+ """.stripMargin)
+ val c :: _ = compileClassesSeparately(codes, extraArgs = compilerArgs)
+ assertInvoke(getMethod(c, "t"), "p1/Implicits$RichFunction1$", "toRx$extension")
+ }
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala
index dd7fbd9977..fa76c0d930 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala
@@ -2,49 +2,40 @@ package scala.tools.nsc
package backend.jvm
package opt
+import org.junit.Assert._
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
-import scala.tools.asm.Opcodes._
-import org.junit.Assert._
+import scala.collection.JavaConverters._
+import scala.tools.asm.Opcodes._
import scala.tools.asm.tree.ClassNode
import scala.tools.nsc.backend.jvm.AsmUtils._
-import scala.tools.testing.AssertUtil._
-
-import CodeGenTools._
-import scala.tools.partest.ASMConverters
-import ASMConverters._
-import scala.tools.testing.ClearAfterClass
-import scala.collection.JavaConverters._
-
-object MethodLevelOptsTest extends ClearAfterClass.Clearable {
- var methodOptCompiler = newCompiler(extraArgs = "-Yopt:l:method")
- def clear(): Unit = { methodOptCompiler = null }
-}
+import scala.tools.partest.ASMConverters._
+import scala.tools.testing.BytecodeTesting
+import scala.tools.testing.BytecodeTesting._
@RunWith(classOf[JUnit4])
-class MethodLevelOptsTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = MethodLevelOptsTest
-
- val methodOptCompiler = MethodLevelOptsTest.methodOptCompiler
+class MethodLevelOptsTest extends BytecodeTesting {
+ override def compilerArgs = "-Yopt:l:method"
+ import compiler._
def wrapInDefault(code: Instruction*) = List(Label(0), LineNumber(1, Label(0))) ::: code.toList ::: List(Label(1))
- def locals(c: ClassNode, m: String) = findAsmMethod(c, m).localVariables.asScala.toList.map(l => (l.name, l.index)).sortBy(_._2)
+ def locals(c: ClassNode, m: String) = getAsmMethod(c, m).localVariables.asScala.toList.map(l => (l.name, l.index)).sortBy(_._2)
@Test
def eliminateEmptyTry(): Unit = {
val code = "def f = { try {} catch { case _: Throwable => 0; () }; 1 }"
val warn = "a pure expression does nothing in statement position"
- assertSameCode(singleMethodInstructions(methodOptCompiler)(code, allowMessage = _.msg contains warn), wrapInDefault(Op(ICONST_1), Op(IRETURN)))
+ assertSameCode(compileInstructions(code, allowMessage = _.msg contains warn), wrapInDefault(Op(ICONST_1), Op(IRETURN)))
}
@Test
def eliminateLoadBoxedUnit(): Unit = {
// the compiler inserts a boxed into the try block. it's therefore non-empty (and live) and not eliminated.
val code = "def f = { try {} catch { case _: Throwable => 0 }; 1 }"
- val m = singleMethod(methodOptCompiler)(code)
+ val m = compileMethod(code)
assertTrue(m.handlers.length == 0)
assertSameCode(m, List(Op(ICONST_1), Op(IRETURN)))
}
@@ -53,7 +44,7 @@ class MethodLevelOptsTest extends ClearAfterClass {
def inlineThrowInCatchNotTry(): Unit = {
// the try block does not contain the `ATHROW` instruction, but in the catch block, `ATHROW` is inlined
val code = "def f(e: Exception) = throw { try e catch { case _: Throwable => e } }"
- val m = singleMethod(methodOptCompiler)(code)
+ val m = compileMethod(code)
assertHandlerLabelPostions(m.handlers.head, m.instructions, 0, 3, 5)
assertSameCode(m.instructions,
wrapInDefault(VarOp(ALOAD, 1), Label(3), Op(ATHROW), Label(5), FrameEntry(4, List(), List("java/lang/Throwable")), Op(POP), VarOp(ALOAD, 1), Op(ATHROW))
@@ -64,7 +55,7 @@ class MethodLevelOptsTest extends ClearAfterClass {
def inlineReturnInCatchNotTry(): Unit = {
val code = "def f: Int = return { try 1 catch { case _: Throwable => 2 } }"
// cannot inline the IRETURN into the try block (because RETURN may throw IllegalMonitorState)
- val m = singleMethod(methodOptCompiler)(code)
+ val m = compileMethod(code)
assertHandlerLabelPostions(m.handlers.head, m.instructions, 0, 3, 5)
assertSameCode(m.instructions,
wrapInDefault(Op(ICONST_1), Label(3), Op(IRETURN), Label(5), FrameEntry(4, List(), List("java/lang/Throwable")), Op(POP), Op(ICONST_2), Op(IRETURN)))
@@ -86,7 +77,7 @@ class MethodLevelOptsTest extends ClearAfterClass {
| println(x)
| }
""".stripMargin
- val m = singleMethod(methodOptCompiler)(code)
+ val m = compileMethod(code)
assertTrue(m.handlers.isEmpty)
assertSameCode(m, List(Op(ICONST_3), Op(IRETURN)))
}
@@ -106,8 +97,8 @@ class MethodLevelOptsTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val List(c) = compileClasses(methodOptCompiler)(code)
- assertSameCode(getSingleMethod(c, "t"), List(
+ val c = compileClass(code)
+ assertSameCode(getMethod(c, "t"), List(
Op(ACONST_NULL), Invoke(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;", false), Op(ARETURN)))
}
@@ -123,9 +114,9 @@ class MethodLevelOptsTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val List(c) = compileClasses(methodOptCompiler)(code)
+ val c = compileClass(code)
assertSameCode(
- getSingleMethod(c, "t"), List(Ldc(LDC, "c"), Op(ARETURN)))
+ getMethod(c, "t"), List(Ldc(LDC, "c"), Op(ARETURN)))
}
@Test
@@ -143,9 +134,9 @@ class MethodLevelOptsTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val List(c) = compileClasses(methodOptCompiler)(code)
+ val c = compileClass(code)
- assertSameCode(getSingleMethod(c, "t"), List(
+ assertSameCode(getMethod(c, "t"), List(
Ldc(LDC, "el"), VarOp(ASTORE, 1),
Field(GETSTATIC, "scala/Predef$", "MODULE$", "Lscala/Predef$;"), VarOp(ALOAD, 1), Invoke(INVOKEVIRTUAL, "scala/Predef$", "println", "(Ljava/lang/Object;)V", false),
Op(ACONST_NULL), VarOp(ASTORE, 1),
@@ -167,8 +158,8 @@ class MethodLevelOptsTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val List(c) = compileClasses(methodOptCompiler)(code)
- assertSameCode(getSingleMethod(c, "t"), List(
+ val c = compileClass(code)
+ assertSameCode(getMethod(c, "t"), List(
IntOp(BIPUSH, 23), IntOp(NEWARRAY, 5), Op(POP), VarOp(ILOAD, 1), VarOp(ILOAD, 2), Op(IADD), Op(IRETURN)))
}
@@ -182,8 +173,8 @@ class MethodLevelOptsTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val List(c) = compileClasses(methodOptCompiler)(code)
- assertSameCode(getSingleMethod(c, "t"), List(
+ val c = compileClass(code)
+ assertSameCode(getMethod(c, "t"), List(
TypeOp(NEW, "java/lang/Integer"), Ldc(LDC, "nono"), Invoke(INVOKESPECIAL, "java/lang/Integer", "<init>", "(Ljava/lang/String;)V", false),
VarOp(ILOAD, 1), VarOp(ILOAD, 2), Op(IADD), Op(IRETURN)))
}
@@ -208,8 +199,8 @@ class MethodLevelOptsTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val List(c) = compileClasses(methodOptCompiler)(code)
- assertSameCode(getSingleMethod(c, "t"), List(Op(ICONST_0), Op(IRETURN)))
+ val c = compileClass(code)
+ assertSameCode(getMethod(c, "t"), List(Op(ICONST_0), Op(IRETURN)))
}
@Test
@@ -224,8 +215,8 @@ class MethodLevelOptsTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val List(c) = compileClasses(methodOptCompiler)(code)
- assertSameCode(getSingleMethod(c, "t"), List(
+ val c = compileClass(code)
+ assertSameCode(getMethod(c, "t"), List(
IntOp(BIPUSH, 30), VarOp(ISTORE, 3), // no constant propagation, so we keep the store (and load below) of a const
VarOp(ILOAD, 1),
VarOp(ILOAD, 2),
@@ -245,8 +236,8 @@ class MethodLevelOptsTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val List(c) = compileClasses(methodOptCompiler)(code)
- val t = getSingleMethod(c, "t")
+ val c = compileClass(code)
+ val t = getMethod(c, "t")
assert(!t.instructions.exists(_.opcode == INVOKEDYNAMIC), t)
}
@@ -326,23 +317,23 @@ class MethodLevelOptsTest extends ClearAfterClass {
|}
""".stripMargin
- val List(c) = compileClasses(methodOptCompiler)(code)
-
- assertNoInvoke(getSingleMethod(c, "t1"))
- assertNoInvoke(getSingleMethod(c, "t2"))
- assertInvoke(getSingleMethod(c, "t3"), "scala/runtime/BoxesRunTime", "unboxToInt")
- assertInvoke(getSingleMethod(c, "t4"), "scala/runtime/BoxesRunTime", "boxToLong")
- assertNoInvoke(getSingleMethod(c, "t5"))
- assertNoInvoke(getSingleMethod(c, "t6"))
- assertNoInvoke(getSingleMethod(c, "t7"))
- assertSameSummary(getSingleMethod(c, "t8"), List(ICONST_0, IRETURN))
- assertNoInvoke(getSingleMethod(c, "t9"))
+ val c = compileClass(code)
+
+ assertNoInvoke(getMethod(c, "t1"))
+ assertNoInvoke(getMethod(c, "t2"))
+ assertInvoke(getMethod(c, "t3"), "scala/runtime/BoxesRunTime", "unboxToInt")
+ assertInvoke(getMethod(c, "t4"), "scala/runtime/BoxesRunTime", "boxToLong")
+ assertNoInvoke(getMethod(c, "t5"))
+ assertNoInvoke(getMethod(c, "t6"))
+ assertNoInvoke(getMethod(c, "t7"))
+ assertSameSummary(getMethod(c, "t8"), List(ICONST_0, IRETURN))
+ assertNoInvoke(getMethod(c, "t9"))
// t10: no invocation of unbox
- assertEquals(getSingleMethod(c, "t10").instructions collect { case Invoke(_, owner, name, _, _) => (owner, name) }, List(
+ assertEquals(getInstructions(c, "t10") collect { case Invoke(_, owner, name, _, _) => (owner, name) }, List(
("java/lang/Integer", "valueOf"),
("C", "escape")))
- assertSameSummary(getSingleMethod(c, "t11"), List(
+ assertSameSummary(getMethod(c, "t11"), List(
BIPUSH, "valueOf", ASTORE /*2*/,
BIPUSH, "valueOf", ASTORE /*3*/,
ALOAD /*0*/, ALOAD /*2*/, "escape",
@@ -350,7 +341,7 @@ class MethodLevelOptsTest extends ClearAfterClass {
ASTORE /*4*/, GETSTATIC /*Predef*/, ALOAD /*4*/, "Integer2int", IRETURN))
// no unbox invocations
- assertEquals(getSingleMethod(c, "t12").instructions collect { case Invoke(_, owner, name, _, _) => (owner, name) }, List(
+ assertEquals(getInstructions(c, "t12") collect { case Invoke(_, owner, name, _, _) => (owner, name) }, List(
("java/lang/Integer", "valueOf"),
("java/lang/Integer", "valueOf"),
("C", "escape")))
@@ -402,14 +393,14 @@ class MethodLevelOptsTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val List(c) = compileClasses(methodOptCompiler)(code)
- assertSameSummary(getSingleMethod(c, "t1"), List(ICONST_0, IRETURN))
- assertNoInvoke(getSingleMethod(c, "t2"))
- assertSameSummary(getSingleMethod(c, "t3"), List(LDC, LDC, LADD, LRETURN))
- assertNoInvoke(getSingleMethod(c, "t4"))
- assertEquals(getSingleMethod(c, "t5").instructions collect { case Field(_, owner, name, _) => s"$owner.$name" },
+ val c = compileClass(code)
+ assertSameSummary(getMethod(c, "t1"), List(ICONST_0, IRETURN))
+ assertNoInvoke(getMethod(c, "t2"))
+ assertSameSummary(getMethod(c, "t3"), List(LDC, LDC, LADD, LRETURN))
+ assertNoInvoke(getMethod(c, "t4"))
+ assertEquals(getInstructions(c, "t5") collect { case Field(_, owner, name, _) => s"$owner.$name" },
List("scala/runtime/IntRef.elem"))
- assertEquals(getSingleMethod(c, "t6").instructions collect { case Field(op, owner, name, _) => s"$op $owner.$name" },
+ assertEquals(getInstructions(c, "t6") collect { case Field(op, owner, name, _) => s"$op $owner.$name" },
List(s"$PUTFIELD scala/runtime/IntRef.elem", s"$GETFIELD scala/runtime/IntRef.elem"))
}
@@ -466,23 +457,23 @@ class MethodLevelOptsTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val List(c) = compileClasses(methodOptCompiler)(code)
- assertNoInvoke(getSingleMethod(c, "t1"))
- assertSameSummary(getSingleMethod(c, "t2"), List(ICONST_1, ICONST_3, IADD, IRETURN))
- assertSameSummary(getSingleMethod(c, "t3"), List(ICONST_3, ICONST_4, IADD, IRETURN))
- assertSameSummary(getSingleMethod(c, "t4"), List(ICONST_3, "boxToInteger", ARETURN))
- assertEquals(getSingleMethod(c, "t5").instructions collect { case Invoke(_, owner, name, _, _) => (owner, name) }, List(
+ val c = compileClass(code)
+ assertNoInvoke(getMethod(c, "t1"))
+ assertSameSummary(getMethod(c, "t2"), List(ICONST_1, ICONST_3, IADD, IRETURN))
+ assertSameSummary(getMethod(c, "t3"), List(ICONST_3, ICONST_4, IADD, IRETURN))
+ assertSameSummary(getMethod(c, "t4"), List(ICONST_3, "boxToInteger", ARETURN))
+ assertEquals(getInstructions(c, "t5") collect { case Invoke(_, owner, name, _, _) => (owner, name) }, List(
("scala/runtime/BoxesRunTime", "boxToInteger"),
("scala/runtime/BoxesRunTime", "boxToInteger"),
("C", "tpl"),
("scala/Tuple2", "_1$mcI$sp")))
- assertSameSummary(getSingleMethod(c, "t6"), List(ICONST_1, ICONST_2, ISUB, IRETURN))
- assertSameSummary(getSingleMethod(c, "t7"), List(
+ assertSameSummary(getMethod(c, "t6"), List(ICONST_1, ICONST_2, ISUB, IRETURN))
+ assertSameSummary(getMethod(c, "t7"), List(
ICONST_1, ICONST_2, ISTORE, ISTORE,
ICONST_3, ISTORE,
ILOAD, ILOAD, IADD, ILOAD, IADD, IRETURN))
- assertNoInvoke(getSingleMethod(c, "t8"))
- assertNoInvoke(getSingleMethod(c, "t9"))
+ assertNoInvoke(getMethod(c, "t8"))
+ assertNoInvoke(getMethod(c, "t9"))
}
@Test
@@ -531,14 +522,14 @@ class MethodLevelOptsTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val List(c) = compileClasses(methodOptCompiler)(code)
- assertSameSummary(getSingleMethod(c, "t1"), List(NEW, DUP, "<init>", ARETURN))
- assertSameCode(getSingleMethod(c, "t2"), List(Op(LCONST_0), Op(LRETURN)))
- assertSameCode(getSingleMethod(c, "t3"), List(Op(ICONST_1), Op(IRETURN)))
- assertSameCode(getSingleMethod(c, "t4"), List(Op(ICONST_1), Op(IRETURN)))
- assertSameCode(getSingleMethod(c, "t5"), List(Op(DCONST_0), Op(DRETURN)))
- assertSameCode(getSingleMethod(c, "t6"), List(Op(ACONST_NULL), Op(ARETURN)))
- assertSameCode(getSingleMethod(c, "t7"), List(Op(ICONST_0), Op(IRETURN)))
+ val c = compileClass(code)
+ assertSameSummary(getMethod(c, "t1"), List(NEW, DUP, "<init>", ARETURN))
+ assertSameCode(getMethod(c, "t2"), List(Op(LCONST_0), Op(LRETURN)))
+ assertSameCode(getMethod(c, "t3"), List(Op(ICONST_1), Op(IRETURN)))
+ assertSameCode(getMethod(c, "t4"), List(Op(ICONST_1), Op(IRETURN)))
+ assertSameCode(getMethod(c, "t5"), List(Op(DCONST_0), Op(DRETURN)))
+ assertSameCode(getMethod(c, "t6"), List(Op(ACONST_NULL), Op(ARETURN)))
+ assertSameCode(getMethod(c, "t7"), List(Op(ICONST_0), Op(IRETURN)))
}
@Test
@@ -551,9 +542,9 @@ class MethodLevelOptsTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val List(c) = compileClasses(methodOptCompiler)(code)
+ val c = compileClass(code)
assertSameCode(
- getSingleMethod(c, "t"), List(
+ getMethod(c, "t"), List(
VarOp(ALOAD, 1), Jump(IFNULL, Label(6)), Op(ICONST_1), Op(IRETURN), Label(6), Op(ICONST_0), Op(IRETURN)))
}
@@ -622,28 +613,28 @@ class MethodLevelOptsTest extends ClearAfterClass {
|}
""".stripMargin
- val List(c) = compileClasses(methodOptCompiler)(code)
- def stores(m: String) = getSingleMethod(c, m).instructions.filter(_.opcode == ASTORE)
+ val c = compileClass(code)
+ def stores(m: String) = getInstructions(c, m).filter(_.opcode == ASTORE)
assertEquals(locals(c, "t1"), List(("this",0), ("kept1",1), ("result",2)))
assert(stores("t1") == List(VarOp(ASTORE, 1), VarOp(ASTORE, 2), VarOp(ASTORE, 1), VarOp(ASTORE, 1)),
- textify(findAsmMethod(c, "t1")))
+ textify(getAsmMethod(c, "t1")))
assertEquals(locals(c, "t2"), List(("this",0), ("kept2",1), ("kept3",2)))
assert(stores("t2") == List(VarOp(ASTORE, 1), VarOp(ASTORE, 2), VarOp(ASTORE, 1)),
- textify(findAsmMethod(c, "t2")))
+ textify(getAsmMethod(c, "t2")))
assertEquals(locals(c, "t3"), List(("this",0), ("kept4",1)))
assert(stores("t3") == List(VarOp(ASTORE, 1), VarOp(ASTORE, 1)),
- textify(findAsmMethod(c, "t3")))
+ textify(getAsmMethod(c, "t3")))
assertEquals(locals(c, "t4"), List(("this",0), ("kept5",1)))
assert(stores("t4") == List(VarOp(ASTORE, 1), VarOp(ASTORE, 1)),
- textify(findAsmMethod(c, "t4")))
+ textify(getAsmMethod(c, "t4")))
assertEquals(locals(c, "t5"), List(("this",0), ("kept6",1)))
assert(stores("t5") == List(VarOp(ASTORE, 1), VarOp(ASTORE, 1)),
- textify(findAsmMethod(c, "t5")))
+ textify(getAsmMethod(c, "t5")))
}
@Test
@@ -690,13 +681,13 @@ class MethodLevelOptsTest extends ClearAfterClass {
|}
""".stripMargin
- val List(c) = compileClasses(methodOptCompiler)(code)
+ val c = compileClass(code)
assertEquals(locals(c, "t1"), List(("this", 0), ("x", 1)))
assertEquals(locals(c, "t2"), List(("this", 0), ("x", 1)))
// we don't have constant propagation (yet).
// the local var can't be optimized as a store;laod sequence, there's a GETSTATIC between the two
- assertSameSummary(getSingleMethod(c, "t2"), List(
+ assertSameSummary(getMethod(c, "t2"), List(
ICONST_2, ISTORE, GETSTATIC, ILOAD, "boxToInteger", "println", RETURN))
assertEquals(locals(c, "t3"), List(("this", 0)))
@@ -718,8 +709,8 @@ class MethodLevelOptsTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val List(c) = compileClasses(methodOptCompiler)(code)
- val t = getSingleMethod(c, "t")
+ val c = compileClass(code)
+ val t = getMethod(c, "t")
assertEquals(t.handlers, Nil)
assertEquals(locals(c, "t"), List(("this", 0)))
assertSameSummary(t, List(GETSTATIC, LDC, "print", -1, GOTO))
@@ -736,8 +727,8 @@ class MethodLevelOptsTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val List(c) = compileClasses(methodOptCompiler)(code)
- assertNoInvoke(getSingleMethod(c, "compare"))
+ val c = compileClass(code)
+ assertNoInvoke(getMethod(c, "compare"))
}
@Test
@@ -750,9 +741,9 @@ class MethodLevelOptsTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val List(c) = compileClasses(methodOptCompiler)(code)
+ val c = compileClass(code)
- assertSameSummary(getSingleMethod(c, "t"), List(
+ assertSameSummary(getMethod(c, "t"), List(
BIPUSH, ILOAD, IF_ICMPNE,
BIPUSH, ILOAD, IF_ICMPNE,
LDC, ASTORE, GOTO,
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala
index 8dd23ec3ce..5bd285f97f 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala
@@ -2,29 +2,20 @@ package scala.tools.nsc
package backend.jvm
package opt
+import org.junit.Assert._
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
-import scala.tools.asm.Opcodes._
-import org.junit.Assert._
-import CodeGenTools._
-import scala.tools.asm.tree.ClassNode
-import scala.tools.nsc.backend.jvm.BTypes.{MethodInlineInfo, InlineInfo}
-import scala.tools.partest.ASMConverters
-import ASMConverters._
import scala.collection.JavaConverters._
-import scala.tools.testing.ClearAfterClass
-
-object ScalaInlineInfoTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler(extraArgs = "-Yopt:l:none")
- def clear(): Unit = { compiler = null }
-}
+import scala.tools.asm.tree.ClassNode
+import scala.tools.nsc.backend.jvm.BTypes.{InlineInfo, MethodInlineInfo}
+import scala.tools.testing.BytecodeTesting
@RunWith(classOf[JUnit4])
-class ScalaInlineInfoTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = ScalaInlineInfoTest
- val compiler = ScalaInlineInfoTest.compiler
+class ScalaInlineInfoTest extends BytecodeTesting {
+ override def compilerArgs = "-Yopt:l:none"
+ import compiler._
def inlineInfo(c: ClassNode): InlineInfo = c.attrs.asScala.collect({ case a: InlineInfoAttribute => a.inlineInfo }).head
@@ -78,7 +69,7 @@ class ScalaInlineInfoTest extends ClearAfterClass {
|}
""".stripMargin
- val cs @ List(c, t, tl, to) = compileClasses(compiler)(code)
+ val cs @ List(c, t, tl, to) = compileClasses(code)
val infoT = inlineInfo(t)
val expectT = InlineInfo (
false, // final class
@@ -155,7 +146,7 @@ class ScalaInlineInfoTest extends ClearAfterClass {
| def nullary: Int
|}
""".stripMargin
- val cs = compileClasses(compiler)(code)
+ val cs = compileClasses(code)
val sams = cs.map(c => (c.name, inlineInfo(c).sam))
assertEquals(sams,
List(
@@ -171,7 +162,7 @@ class ScalaInlineInfoTest extends ClearAfterClass {
@Test
def lzyComputeInlineInfo(): Unit = {
val code = "class C { object O }"
- val List(c, om) = compileClasses(compiler)(code)
+ val List(c, om) = compileClasses(code)
val infoC = inlineInfo(c)
val expected = Map(
"<init>()V" -> MethodInlineInfo(false,false,false),
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala
index 99acb318de..992a0e541b 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala
@@ -2,15 +2,15 @@ package scala.tools.nsc
package backend.jvm
package opt
+import org.junit.Assert._
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
-import scala.tools.asm.Opcodes._
-import org.junit.Assert._
-import CodeGenTools._
+import scala.tools.asm.Opcodes._
import scala.tools.partest.ASMConverters
-import ASMConverters._
+import scala.tools.partest.ASMConverters._
+import scala.tools.testing.BytecodeTesting._
@RunWith(classOf[JUnit4])
class SimplifyJumpsTest {
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala
index 0021a1784d..63bbcc396b 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala
@@ -2,44 +2,28 @@ package scala.tools.nsc
package backend.jvm
package opt
+import org.junit.Assert._
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
-import scala.tools.asm.Opcodes._
-import org.junit.Assert._
+import scala.tools.asm.Opcodes._
+import scala.tools.partest.ASMConverters._
import scala.tools.testing.AssertUtil._
-
-import CodeGenTools._
-import scala.tools.partest.ASMConverters
-import ASMConverters._
+import scala.tools.testing.BytecodeTesting._
import scala.tools.testing.ClearAfterClass
-object UnreachableCodeTest extends ClearAfterClass.Clearable {
- // jvm-1.6 enables emitting stack map frames, which impacts the code generation wrt dead basic blocks,
- // see comment in BCodeBodyBuilder
- var methodOptCompiler = newCompiler(extraArgs = "-Yopt:l:method")
- var dceCompiler = newCompiler(extraArgs = "-Yopt:unreachable-code")
- var noOptCompiler = newCompiler(extraArgs = "-Yopt:l:none")
-
- def clear(): Unit = {
- methodOptCompiler = null
- dceCompiler = null
- noOptCompiler = null
- }
-}
-
@RunWith(classOf[JUnit4])
class UnreachableCodeTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = UnreachableCodeTest
-
- val methodOptCompiler = UnreachableCodeTest.methodOptCompiler
- val dceCompiler = UnreachableCodeTest.dceCompiler
- val noOptCompiler = UnreachableCodeTest.noOptCompiler
+ // jvm-1.6 enables emitting stack map frames, which impacts the code generation wrt dead basic blocks,
+ // see comment in BCodeBodyBuilder
+ val methodOptCompiler = cached("methodOptCompiler", () => newCompiler(extraArgs = "-Yopt:l:method"))
+ val dceCompiler = cached("dceCompiler", () => newCompiler(extraArgs = "-Yopt:unreachable-code"))
+ val noOptCompiler = cached("noOptCompiler", () => newCompiler(extraArgs = "-Yopt:l:none"))
def assertEliminateDead(code: (Instruction, Boolean)*): Unit = {
val method = genMethod()(code.map(_._1): _*)
- dceCompiler.genBCode.bTypes.localOpt.removeUnreachableCodeImpl(method, "C")
+ dceCompiler.global.genBCode.bTypes.localOpt.removeUnreachableCodeImpl(method, "C")
val nonEliminated = instructionsFromMethod(method)
val expectedLive = code.filter(_._2).map(_._1).toList
assertSameCode(nonEliminated, expectedLive)
@@ -126,10 +110,10 @@ class UnreachableCodeTest extends ClearAfterClass {
@Test
def basicEliminationCompiler(): Unit = {
val code = "def f: Int = { return 1; 2 }"
- val withDce = singleMethodInstructions(dceCompiler)(code)
+ val withDce = dceCompiler.compileInstructions(code)
assertSameCode(withDce.dropNonOp, List(Op(ICONST_1), Op(IRETURN)))
- val noDce = singleMethodInstructions(noOptCompiler)(code)
+ val noDce = noOptCompiler.compileInstructions(code)
// The emitted code is ICONST_1, IRETURN, ICONST_2, IRETURN. The latter two are dead.
//
@@ -155,23 +139,23 @@ class UnreachableCodeTest extends ClearAfterClass {
def wrapInDefault(code: Instruction*) = List(Label(0), LineNumber(1, Label(0))) ::: code.toList ::: List(Label(1))
val code = "def f: Int = { return 0; try { 1 } catch { case _: Exception => 2 } }"
- val m = singleMethod(dceCompiler)(code)
+ val m = dceCompiler.compileMethod(code)
assertTrue(m.handlers.isEmpty) // redundant (if code is gone, handler is gone), but done once here for extra safety
assertSameCode(m.instructions,
wrapInDefault(Op(ICONST_0), Op(IRETURN)))
val code2 = "def f: Unit = { try { } catch { case _: Exception => () }; () }"
// requires fixpoint optimization of methodOptCompiler (dce alone is not enough): first the handler is eliminated, then it's dead catch block.
- assertSameCode(singleMethodInstructions(methodOptCompiler)(code2), wrapInDefault(Op(RETURN)))
+ assertSameCode(methodOptCompiler.compileInstructions(code2), wrapInDefault(Op(RETURN)))
val code3 = "def f: Unit = { try { } catch { case _: Exception => try { } catch { case _: Exception => () } }; () }"
- assertSameCode(singleMethodInstructions(methodOptCompiler)(code3), wrapInDefault(Op(RETURN)))
+ assertSameCode(methodOptCompiler.compileInstructions(code3), wrapInDefault(Op(RETURN)))
// this example requires two iterations to get rid of the outer handler.
// the first iteration of DCE cannot remove the inner handler. then the inner (empty) handler is removed.
// then the second iteration of DCE removes the inner catch block, and then the outer handler is removed.
val code4 = "def f: Unit = { try { try { } catch { case _: Exception => () } } catch { case _: Exception => () }; () }"
- assertSameCode(singleMethodInstructions(methodOptCompiler)(code4), wrapInDefault(Op(RETURN)))
+ assertSameCode(methodOptCompiler.compileInstructions(code4), wrapInDefault(Op(RETURN)))
}
@Test // test the dce-testing tools
@@ -188,7 +172,7 @@ class UnreachableCodeTest extends ClearAfterClass {
}
@Test
- def bytecodeEquivalence: Unit = {
+ def bytecodeEquivalence(): Unit = {
assertTrue(List(VarOp(ILOAD, 1)) ===
List(VarOp(ILOAD, 2)))
assertTrue(List(VarOp(ILOAD, 1), VarOp(ISTORE, 1)) ===
@@ -230,35 +214,35 @@ class UnreachableCodeTest extends ClearAfterClass {
| def t4 = cons(nt)
|}
""".stripMargin
- val List(c) = compileClasses(noOptCompiler)(code)
+ val c = noOptCompiler.compileClass(code)
- assertSameSummary(getSingleMethod(c, "nl"), List(ACONST_NULL, ARETURN))
+ assertSameSummary(getMethod(c, "nl"), List(ACONST_NULL, ARETURN))
- assertSameSummary(getSingleMethod(c, "nt"), List(
+ assertSameSummary(getMethod(c, "nt"), List(
NEW, DUP, LDC, "<init>", ATHROW))
- assertSameSummary(getSingleMethod(c, "t1"), List(
+ assertSameSummary(getMethod(c, "t1"), List(
ALOAD, ACONST_NULL, "cons", RETURN))
// GenBCode introduces POP; ACONST_NULL after loading an expression of type scala.runtime.Null$,
// see comment in BCodeBodyBuilder.adapt
- assertSameSummary(getSingleMethod(c, "t2"), List(
+ assertSameSummary(getMethod(c, "t2"), List(
ALOAD, ALOAD, "nl", POP, ACONST_NULL, "cons", RETURN))
// the bytecode generated by GenBCode is ... ATHROW; INVOKEVIRTUAL C.cons; RETURN
// the ASM classfile writer creates a new basic block (creates a label) right after the ATHROW
// and replaces all instructions by NOP*; ATHROW, see comment in BCodeBodyBuilder.adapt
// NOTE: DCE is enabled by default and gets rid of the redundant code (tested below)
- assertSameSummary(getSingleMethod(c, "t3"), List(
+ assertSameSummary(getMethod(c, "t3"), List(
ALOAD, NEW, DUP, LDC, "<init>", ATHROW, NOP, NOP, NOP, ATHROW))
// GenBCode introduces an ATHROW after the invocation of C.nt, see BCodeBodyBuilder.adapt
// NOTE: DCE is enabled by default and gets rid of the redundant code (tested below)
- assertSameSummary(getSingleMethod(c, "t4"), List(
+ assertSameSummary(getMethod(c, "t4"), List(
ALOAD, ALOAD, "nt", ATHROW, NOP, NOP, NOP, ATHROW))
- val List(cDCE) = compileClasses(dceCompiler)(code)
- assertSameSummary(getSingleMethod(cDCE, "t3"), List(ALOAD, NEW, DUP, LDC, "<init>", ATHROW))
- assertSameSummary(getSingleMethod(cDCE, "t4"), List(ALOAD, ALOAD, "nt", ATHROW))
+ val cDCE = dceCompiler.compileClass(code)
+ assertSameSummary(getMethod(cDCE, "t3"), List(ALOAD, NEW, DUP, LDC, "<init>", ATHROW))
+ assertSameSummary(getMethod(cDCE, "t4"), List(ALOAD, ALOAD, "nt", ATHROW))
}
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/UnusedLocalVariablesTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/UnusedLocalVariablesTest.scala
index 4f71df1822..c9c98b403b 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/UnusedLocalVariablesTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/UnusedLocalVariablesTest.scala
@@ -2,28 +2,20 @@ package scala.tools.nsc
package backend.jvm
package opt
+import org.junit.Assert._
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
-import scala.tools.asm.Opcodes._
-import org.junit.Assert._
-import scala.collection.JavaConverters._
-import CodeGenTools._
-import scala.tools.partest.ASMConverters
-import ASMConverters._
-import scala.tools.testing.ClearAfterClass
-
-object UnusedLocalVariablesTest extends ClearAfterClass.Clearable {
- var dceCompiler = newCompiler(extraArgs = "-Yopt:unreachable-code")
- def clear(): Unit = { dceCompiler = null }
-}
+import scala.collection.JavaConverters._
+import scala.tools.partest.ASMConverters._
+import scala.tools.testing.BytecodeTesting
+import scala.tools.testing.BytecodeTesting._
@RunWith(classOf[JUnit4])
-class UnusedLocalVariablesTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = UnusedLocalVariablesTest
-
- val dceCompiler = UnusedLocalVariablesTest.dceCompiler
+class UnusedLocalVariablesTest extends BytecodeTesting {
+ override def compilerArgs = "-Yopt:unreachable-code"
+ import compiler._
@Test
def removeUnusedVar(): Unit = {
@@ -56,7 +48,7 @@ class UnusedLocalVariablesTest extends ClearAfterClass {
| }
|}
|""".stripMargin
- val cls = compileClasses(dceCompiler)(code).head
+ val cls = compileClass(code)
val m = convertMethod(cls.methods.asScala.toList.find(_.desc == "(I)V").get)
assertTrue(m.localVars.length == 2) // this, a, but not y
@@ -77,19 +69,14 @@ class UnusedLocalVariablesTest extends ClearAfterClass {
|}
""".stripMargin
- val clss2 = compileClasses(dceCompiler)(code2)
- val cls2 = clss2.find(_.name == "C").get
- val companion2 = clss2.find(_.name == "C$").get
-
- val clsConstr = convertMethod(cls2.methods.asScala.toList.find(_.name == "<init>").get)
- val companionConstr = convertMethod(companion2.methods.asScala.toList.find(_.name == "<init>").get)
+ val List(cls2, companion2) = compileClasses(code2)
- assertTrue(clsConstr.localVars.length == 1) // this
- assertTrue(companionConstr.localVars.length == 1) // this
+ assertTrue(getMethod(cls2, "<init>").localVars.length == 1) // this
+ assertTrue(getMethod(companion2, "<init>").localVars.length == 1) // this
}
def assertLocalVarCount(code: String, numVars: Int): Unit = {
- assertTrue(singleMethod(dceCompiler)(code).localVars.length == numVars)
+ assertTrue(compileMethod(code).localVars.length == numVars)
}
}
diff --git a/test/junit/scala/tools/nsc/interpreter/ScriptedTest.scala b/test/junit/scala/tools/nsc/interpreter/ScriptedTest.scala
new file mode 100644
index 0000000000..a8dc8eb3e0
--- /dev/null
+++ b/test/junit/scala/tools/nsc/interpreter/ScriptedTest.scala
@@ -0,0 +1,83 @@
+package scala.tools.nsc
+package interpreter
+
+import org.junit._, Assert._, runner.RunWith, runners.JUnit4
+import scala.tools.testing.AssertUtil.assertThrows
+
+@RunWith(classOf[JUnit4])
+class ScriptedTest {
+ import javax.script._
+ import scala.tools.nsc.interpreter.Scripted
+
+ def scripted: ScriptEngine with Compilable = Scripted()
+ // same as by service discovery
+ //new ScriptEngineManager().getEngineByName("scala").asInstanceOf[ScriptEngine with Compilable]
+
+ @Test def eval() = {
+ val engine = scripted
+ engine.put("foo","bar")
+ assert("bar" == engine.eval("foo"))
+ val bindings = engine.createBindings()
+ bindings.put("foo","baz")
+ assert("baz" == engine.eval("foo", bindings))
+ val c = engine.compile("def f = foo.asInstanceOf[String] ; f * 2")
+ assert("barbar" == c.eval())
+ assert("bazbaz" == c.eval(bindings))
+ }
+ @Test def `SI-7933 multiple eval compiled script`() = {
+ val engine = scripted
+ val init = """val i = new java.util.concurrent.atomic.AtomicInteger"""
+ val code = """i.getAndIncrement()"""
+ engine eval init
+ val c = engine compile code
+ assert(0 == c.eval())
+ assert(1 == c.eval())
+ }
+ @Test def `SI-8422 captured i/o`() = {
+ import java.io.StringWriter
+ val engine = scripted
+ val ctx = new SimpleScriptContext
+ val w = new StringWriter
+ val code = """print("hello, world")"""
+
+ ctx.setWriter(w)
+ engine.eval(code, ctx)
+ assertEquals("hello, world", w.toString)
+ }
+ @Test def `SI-8422 captured multi i/o`() = {
+ import java.io.{ StringWriter, StringReader }
+ import scala.compat.Platform.EOL
+ val engine = scripted
+ val ctx = new SimpleScriptContext
+ val out = new StringWriter
+ val err = new StringWriter
+ val text =
+ """Now is the time
+ |for all good
+ |dogs to come for supper.""".stripMargin
+ val in = new StringReader(text)
+
+ val code =
+ """var s: String = _
+ |var i: Int = 0
+ |do {
+ | s = scala.io.StdIn.readLine()
+ | val out = if ((i & 1) == 0) Console.out else Console.err
+ | i += 1
+ | Option(s) foreach out.println
+ |} while (s != null)""".stripMargin
+
+ ctx.setWriter(out)
+ ctx.setErrorWriter(err)
+ ctx.setReader(in)
+ engine.eval(code, ctx)
+ val lines = text.lines.toList
+ assertEquals(lines.head + EOL + lines.last + EOL, out.toString)
+ assertEquals(lines(1) + EOL, err.toString)
+ }
+ @Test def `on compile error`(): Unit = {
+ val engine = scripted
+ val err = "not found: value foo in def f = foo at line number 11 at column number 16"
+ assertThrows[ScriptException](engine.compile("def f = foo"), _ == err)
+ }
+}
diff --git a/test/junit/scala/tools/nsc/transform/delambdafy/DelambdafyTest.scala b/test/junit/scala/tools/nsc/transform/delambdafy/DelambdafyTest.scala
index e4bf038f32..609f481721 100644
--- a/test/junit/scala/tools/nsc/transform/delambdafy/DelambdafyTest.scala
+++ b/test/junit/scala/tools/nsc/transform/delambdafy/DelambdafyTest.scala
@@ -1,17 +1,15 @@
package scala.tools.nsc.transform.delambdafy
-import scala.reflect.io.Path.jfile2path
-import scala.tools.nsc.backend.jvm.CodeGenTools.getGeneratedClassfiles
-import scala.tools.nsc.backend.jvm.CodeGenTools.makeSourceFile
-import scala.tools.nsc.backend.jvm.CodeGenTools.newCompilerWithoutVirtualOutdir
-import scala.tools.nsc.io.AbstractFile
-import scala.tools.testing.TempDir
-
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
+import scala.reflect.io.Path.jfile2path
+import scala.tools.nsc.io.AbstractFile
+import scala.tools.testing.BytecodeTesting._
+import scala.tools.testing.TempDir
+
@RunWith(classOf[JUnit4])
class DelambdafyTest {
def compileToMultipleOutputWithDelamdbafyMethod(): List[(String, Array[Byte])] = {
@@ -55,9 +53,9 @@ object Delambdafy {
val extraArgs = "-Ydelambdafy:method"
val argsWithOutDir = extraArgs + s" -d $outDirPath -cp $outDirPath"
val compiler = newCompilerWithoutVirtualOutdir(extraArgs = argsWithOutDir)
- compiler.settings.outputDirs.add(srcFile.file, outDir)
+ compiler.global.settings.outputDirs.add(srcFile.file, outDir)
- new compiler.Run().compileSources(List(srcFile))
+ new compiler.global.Run().compileSources(List(srcFile))
val classfiles = getGeneratedClassfiles(outDir)
outDir.delete()
diff --git a/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala b/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala
index ac558e2e21..b6e8d4fbf2 100644
--- a/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala
+++ b/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala
@@ -1,33 +1,20 @@
package scala.tools.nsc
package transform.patmat
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.junit.Test
-import scala.tools.asm.Opcodes._
-import org.junit.Assert._
+import scala.tools.asm.Opcodes._
import scala.tools.nsc.backend.jvm.AsmUtils._
-import scala.tools.nsc.backend.jvm.CodeGenTools
-import scala.tools.testing.AssertUtil._
-
-import CodeGenTools._
-import scala.tools.partest.ASMConverters
-import ASMConverters._
-import scala.tools.testing.ClearAfterClass
-
-object PatmatBytecodeTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler()
- var optCompiler = newCompiler(extraArgs = "-Yopt:l:project")
- def clear(): Unit = { compiler = null; optCompiler = null }
-}
+import scala.tools.testing.BytecodeTesting
+import scala.tools.testing.BytecodeTesting._
@RunWith(classOf[JUnit4])
-class PatmatBytecodeTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = PatmatBytecodeTest
+class PatmatBytecodeTest extends BytecodeTesting {
+ val optCompiler = cached("optCompiler", () => newCompiler(extraArgs = "-Yopt:l:project"))
- val compiler = PatmatBytecodeTest.compiler
- val optCompiler = PatmatBytecodeTest.optCompiler
+ import compiler._
@Test
def t6956(): Unit = {
@@ -51,9 +38,9 @@ class PatmatBytecodeTest extends ClearAfterClass {
|}
""".stripMargin
- val List(c) = compileClasses(compiler)(code)
- assert(getSingleMethod(c, "s1").instructions.count(_.opcode == TABLESWITCH) == 1, textify(c))
- assert(getSingleMethod(c, "s2").instructions.count(_.opcode == TABLESWITCH) == 1, textify(c))
+ val c = compileClass(code)
+ assert(getInstructions(c, "s1").count(_.opcode == TABLESWITCH) == 1, textify(c))
+ assert(getInstructions(c, "s2").count(_.opcode == TABLESWITCH) == 1, textify(c))
}
@Test
@@ -79,9 +66,9 @@ class PatmatBytecodeTest extends ClearAfterClass {
|}
""".stripMargin
- val List(c) = compileClasses(compiler)(code)
- assert(getSingleMethod(c, "s1").instructions.count(_.opcode == TABLESWITCH) == 1, textify(c))
- assert(getSingleMethod(c, "s2").instructions.count(_.opcode == TABLESWITCH) == 1, textify(c))
+ val c = compileClass(code)
+ assert(getInstructions(c, "s1").count(_.opcode == TABLESWITCH) == 1, textify(c))
+ assert(getInstructions(c, "s2").count(_.opcode == TABLESWITCH) == 1, textify(c))
}
@Test
@@ -94,9 +81,9 @@ class PatmatBytecodeTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val c = compileClasses(optCompiler)(code).head
+ val c :: _ = optCompiler.compileClasses(code)
- assertSameSummary(getSingleMethod(c, "a"), List(
+ assertSameSummary(getMethod(c, "a"), List(
NEW, DUP, ICONST_1, LDC, "<init>",
"y", ARETURN))
}
@@ -111,8 +98,8 @@ class PatmatBytecodeTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val c = compileClasses(optCompiler)(code).head
- assert(!getSingleMethod(c, "a").instructions.exists(i => i.opcode == IFNULL || i.opcode == IFNONNULL), textify(findAsmMethod(c, "a")))
+ val c :: _ = optCompiler.compileClasses(code)
+ assert(!getInstructions(c, "a").exists(i => i.opcode == IFNULL || i.opcode == IFNONNULL), textify(getAsmMethod(c, "a")))
}
@Test
@@ -125,8 +112,8 @@ class PatmatBytecodeTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val c = compileClasses(optCompiler)(code).head
- assertSameSummary(getSingleMethod(c, "a"), List(
+ val c :: _ = optCompiler.compileClasses(code)
+ assertSameSummary(getMethod(c, "a"), List(
NEW, DUP, ICONST_1, "boxToInteger", LDC, "<init>", ASTORE /*1*/,
ALOAD /*1*/, "y", ASTORE /*2*/,
ALOAD /*1*/, "x", INSTANCEOF, IFNE /*R*/,
@@ -146,7 +133,7 @@ class PatmatBytecodeTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val c = compileClasses(optCompiler)(code, allowMessage = _.msg.contains("may not be exhaustive")).head
+ val c = optCompiler.compileClass(code, allowMessage = _.msg.contains("may not be exhaustive"))
val expected = List(
ALOAD /*1*/ , INSTANCEOF /*::*/ , IFEQ /*A*/ ,
@@ -155,8 +142,8 @@ class PatmatBytecodeTest extends ClearAfterClass {
-1 /*A*/ , NEW /*MatchError*/ , DUP, ALOAD /*1*/ , "<init>", ATHROW,
-1 /*B*/ , ILOAD, IRETURN)
- assertSameSummary(getSingleMethod(c, "a"), expected)
- assertSameSummary(getSingleMethod(c, "b"), expected)
+ assertSameSummary(getMethod(c, "a"), expected)
+ assertSameSummary(getMethod(c, "b"), expected)
}
@Test
@@ -178,18 +165,18 @@ class PatmatBytecodeTest extends ClearAfterClass {
| def t9 = { val C(a, _) = C("hi", 23); a.toString }
|}
""".stripMargin
- val List(c, cMod) = compileClasses(optCompiler)(code)
- assertSameSummary(getSingleMethod(c, "t1"), List(ICONST_1, ICONST_2, IADD, IRETURN))
- assertSameSummary(getSingleMethod(c, "t2"), List(ICONST_1, IRETURN))
- assertInvokedMethods(getSingleMethod(c, "t3"), List("C.tplCall", "scala/Tuple2._1", "scala/Tuple2._2$mcI$sp", "scala/MatchError.<init>", "java/lang/String.length"))
- assertInvokedMethods(getSingleMethod(c, "t4"), List("C.tplCall", "scala/Tuple2._2$mcI$sp", "scala/MatchError.<init>"))
- assertNoInvoke(getSingleMethod(c, "t5"))
- assertSameSummary(getSingleMethod(c, "t6"), List(BIPUSH, IRETURN))
+ val List(c, cMod) = optCompiler.compileClasses(code)
+ assertSameSummary(getMethod(c, "t1"), List(ICONST_1, ICONST_2, IADD, IRETURN))
+ assertSameSummary(getMethod(c, "t2"), List(ICONST_1, IRETURN))
+ assertInvokedMethods(getMethod(c, "t3"), List("C.tplCall", "scala/Tuple2._1", "scala/Tuple2._2$mcI$sp", "scala/MatchError.<init>", "java/lang/String.length"))
+ assertInvokedMethods(getMethod(c, "t4"), List("C.tplCall", "scala/Tuple2._2$mcI$sp", "scala/MatchError.<init>"))
+ assertNoInvoke(getMethod(c, "t5"))
+ assertSameSummary(getMethod(c, "t6"), List(BIPUSH, IRETURN))
// MatchError reachable because of the type pattern `s: String`
- assertInvokedMethods(getSingleMethod(c, "t7"), List("C.a", "C.b", "scala/MatchError.<init>", "java/lang/String.length"))
- assertSameSummary(getSingleMethod(c, "t8"), List(ALOAD, "b", IRETURN))
+ assertInvokedMethods(getMethod(c, "t7"), List("C.a", "C.b", "scala/MatchError.<init>", "java/lang/String.length"))
+ assertSameSummary(getMethod(c, "t8"), List(ALOAD, "b", IRETURN))
// C allocation not eliminated - constructor may have side-effects.
- assertSameSummary(getSingleMethod(c, "t9"), List(NEW, DUP, LDC, BIPUSH, "<init>", "a", "toString", ARETURN))
+ assertSameSummary(getMethod(c, "t9"), List(NEW, DUP, LDC, BIPUSH, "<init>", "a", "toString", ARETURN))
}
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala b/test/junit/scala/tools/testing/BytecodeTesting.scala
index 389e5b2ead..b11ad27148 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala
+++ b/test/junit/scala/tools/testing/BytecodeTesting.scala
@@ -1,32 +1,117 @@
-package scala.tools.nsc.backend.jvm
+package scala.tools.testing
import org.junit.Assert._
+import scala.collection.JavaConverters._
import scala.collection.mutable.ListBuffer
import scala.reflect.internal.util.BatchSourceFile
import scala.reflect.io.VirtualDirectory
import scala.tools.asm.Opcodes
import scala.tools.asm.tree.{AbstractInsnNode, ClassNode, MethodNode}
import scala.tools.cmd.CommandLineParser
+import scala.tools.nsc.backend.jvm.AsmUtils
+import scala.tools.nsc.backend.jvm.AsmUtils._
import scala.tools.nsc.io.AbstractFile
import scala.tools.nsc.reporters.StoreReporter
-import scala.tools.nsc.settings.MutableSettings
-import scala.tools.nsc.{Settings, Global}
-import scala.tools.partest.ASMConverters
-import scala.collection.JavaConverters._
-import scala.tools.testing.TempDir
-import AsmUtils._
-
-object CodeGenTools {
- import ASMConverters._
-
- def genMethod( flags: Int = Opcodes.ACC_PUBLIC,
- name: String = "m",
- descriptor: String = "()V",
- genericSignature: String = null,
- throwsExceptions: Array[String] = null,
- handlers: List[ExceptionHandler] = Nil,
- localVars: List[LocalVariable] = Nil)(body: Instruction*): MethodNode = {
+import scala.tools.nsc.{Global, Settings}
+import scala.tools.partest.ASMConverters._
+
+trait BytecodeTesting extends ClearAfterClass {
+ def compilerArgs = "" // to be overridden
+ val compiler = cached("compiler", () => BytecodeTesting.newCompiler(extraArgs = compilerArgs))
+}
+
+class Compiler(val global: Global) {
+ import BytecodeTesting._
+
+ def resetOutput(): Unit = {
+ global.settings.outputDirs.setSingleOutput(new VirtualDirectory("(memory)", None))
+ }
+
+ private def newRun: global.Run = {
+ global.reporter.reset()
+ resetOutput()
+ new global.Run()
+ }
+
+ private def reporter = global.reporter.asInstanceOf[StoreReporter]
+
+ def checkReport(allowMessage: StoreReporter#Info => Boolean = _ => false): Unit = {
+ val disallowed = reporter.infos.toList.filter(!allowMessage(_)) // toList prevents an infer-non-wildcard-existential warning.
+ if (disallowed.nonEmpty) {
+ val msg = disallowed.mkString("\n")
+ assert(false, "The compiler issued non-allowed warnings or errors:\n" + msg)
+ }
+ }
+
+ def compileToBytes(scalaCode: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): List[(String, Array[Byte])] = {
+ val run = newRun
+ run.compileSources(makeSourceFile(scalaCode, "unitTestSource.scala") :: javaCode.map(p => makeSourceFile(p._1, p._2)))
+ checkReport(allowMessage)
+ getGeneratedClassfiles(global.settings.outputDirs.getSingleOutput.get)
+ }
+
+ def compileClasses(code: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): List[ClassNode] = {
+ readAsmClasses(compileToBytes(code, javaCode, allowMessage))
+ }
+
+ def compileClass(code: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): ClassNode = {
+ val List(c) = compileClasses(code, javaCode, allowMessage)
+ c
+ }
+
+ def compileToBytesTransformed(scalaCode: String, javaCode: List[(String, String)] = Nil, beforeBackend: global.Tree => global.Tree): List[(String, Array[Byte])] = {
+ import global._
+ settings.stopBefore.value = "jvm" :: Nil
+ val run = newRun
+ val scalaUnit = newCompilationUnit(scalaCode, "unitTestSource.scala")
+ val javaUnits = javaCode.map(p => newCompilationUnit(p._1, p._2))
+ val units = scalaUnit :: javaUnits
+ run.compileUnits(units, run.parserPhase)
+ settings.stopBefore.value = Nil
+ scalaUnit.body = beforeBackend(scalaUnit.body)
+ checkReport(_ => false)
+ val run1 = newRun
+ run1.compileUnits(units, run1.phaseNamed("jvm"))
+ checkReport(_ => false)
+ getGeneratedClassfiles(settings.outputDirs.getSingleOutput.get)
+ }
+
+ def compileClassesTransformed(scalaCode: String, javaCode: List[(String, String)] = Nil, beforeBackend: global.Tree => global.Tree): List[ClassNode] =
+ readAsmClasses(compileToBytesTransformed(scalaCode, javaCode, beforeBackend))
+
+ def compileAsmMethods(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): List[MethodNode] = {
+ val c = compileClass(s"class C { $code }", allowMessage = allowMessage)
+ getAsmMethods(c, _ != "<init>")
+ }
+
+ def compileAsmMethod(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): MethodNode = {
+ val List(m) = compileAsmMethods(code, allowMessage)
+ m
+ }
+
+ def compileMethods(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): List[Method] =
+ compileAsmMethods(code, allowMessage).map(convertMethod)
+
+ def compileMethod(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): Method = {
+ val List(m) = compileMethods(code, allowMessage = allowMessage)
+ m
+ }
+
+ def compileInstructions(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): List[Instruction] = {
+ val List(m) = compileMethods(code, allowMessage = allowMessage)
+ m.instructions
+ }
+}
+
+object BytecodeTesting {
+ def genMethod(flags: Int = Opcodes.ACC_PUBLIC,
+ name: String = "m",
+ descriptor: String = "()V",
+ genericSignature: String = null,
+ throwsExceptions: Array[String] = null,
+ handlers: List[ExceptionHandler] = Nil,
+ localVars: List[LocalVariable] = Nil)(body: Instruction*): MethodNode = {
val node = new MethodNode(flags, name, descriptor, genericSignature, throwsExceptions)
applyToMethod(node, Method(body.toList, handlers, localVars))
node
@@ -39,33 +124,21 @@ object CodeGenTools {
cls
}
- private def resetOutput(compiler: Global): Unit = {
- compiler.settings.outputDirs.setSingleOutput(new VirtualDirectory("(memory)", None))
- }
-
- def newCompiler(defaultArgs: String = "-usejavacp", extraArgs: String = ""): Global = {
+ def newCompiler(defaultArgs: String = "-usejavacp", extraArgs: String = ""): Compiler = {
val compiler = newCompilerWithoutVirtualOutdir(defaultArgs, extraArgs)
- resetOutput(compiler)
+ compiler.resetOutput()
compiler
}
- def newCompilerWithoutVirtualOutdir(defaultArgs: String = "-usejavacp", extraArgs: String = ""): Global = {
+ def newCompilerWithoutVirtualOutdir(defaultArgs: String = "-usejavacp", extraArgs: String = ""): Compiler = {
def showError(s: String) = throw new Exception(s)
val settings = new Settings(showError)
val args = (CommandLineParser tokenize defaultArgs) ++ (CommandLineParser tokenize extraArgs)
val (_, nonSettingsArgs) = settings.processArguments(args, processAll = true)
if (nonSettingsArgs.nonEmpty) showError("invalid compiler flags: " + nonSettingsArgs.mkString(" "))
- new Global(settings, new StoreReporter)
- }
-
- def newRun(compiler: Global): compiler.Run = {
- compiler.reporter.reset()
- resetOutput(compiler)
- new compiler.Run()
+ new Compiler(new Global(settings, new StoreReporter))
}
- def reporter(compiler: Global) = compiler.reporter.asInstanceOf[StoreReporter]
-
def makeSourceFile(code: String, filename: String): BatchSourceFile = new BatchSourceFile(filename, code)
def getGeneratedClassfiles(outDir: AbstractFile): List[(String, Array[Byte])] = {
@@ -80,38 +153,6 @@ object CodeGenTools {
files(outDir)
}
- def checkReport(compiler: Global, allowMessage: StoreReporter#Info => Boolean = _ => false): Unit = {
- val disallowed = reporter(compiler).infos.toList.filter(!allowMessage(_)) // toList prevents an infer-non-wildcard-existential warning.
- if (disallowed.nonEmpty) {
- val msg = disallowed.mkString("\n")
- assert(false, "The compiler issued non-allowed warnings or errors:\n" + msg)
- }
- }
-
- def compile(compiler: Global)(scalaCode: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): List[(String, Array[Byte])] = {
- val run = newRun(compiler)
- run.compileSources(makeSourceFile(scalaCode, "unitTestSource.scala") :: javaCode.map(p => makeSourceFile(p._1, p._2)))
- checkReport(compiler, allowMessage)
- getGeneratedClassfiles(compiler.settings.outputDirs.getSingleOutput.get)
- }
-
- def compileTransformed(compiler: Global)(scalaCode: String, javaCode: List[(String, String)] = Nil, beforeBackend: compiler.Tree => compiler.Tree): List[(String, Array[Byte])] = {
- compiler.settings.stopBefore.value = "jvm" :: Nil
- val run = newRun(compiler)
- import compiler._
- val scalaUnit = newCompilationUnit(scalaCode, "unitTestSource.scala")
- val javaUnits = javaCode.map(p => newCompilationUnit(p._1, p._2))
- val units = scalaUnit :: javaUnits
- run.compileUnits(units, run.parserPhase)
- compiler.settings.stopBefore.value = Nil
- scalaUnit.body = beforeBackend(scalaUnit.body)
- checkReport(compiler, _ => false)
- val run1 = newRun(compiler)
- run1.compileUnits(units, run1.phaseNamed("jvm"))
- checkReport(compiler, _ => false)
- getGeneratedClassfiles(compiler.settings.outputDirs.getSingleOutput.get)
- }
-
/**
* Compile multiple Scala files separately into a single output directory.
*
@@ -121,15 +162,15 @@ object CodeGenTools {
* The output directory is a physical directory, I have not figured out if / how it's possible to
* add a VirtualDirectory to the classpath of a compiler.
*/
- def compileSeparately(codes: List[String], extraArgs: String = "", allowMessage: StoreReporter#Info => Boolean = _ => false, afterEach: AbstractFile => Unit = _ => ()): List[(String, Array[Byte])] = {
+ def compileToBytesSeparately(codes: List[String], extraArgs: String = "", allowMessage: StoreReporter#Info => Boolean = _ => false, afterEach: AbstractFile => Unit = _ => ()): List[(String, Array[Byte])] = {
val outDir = AbstractFile.getDirectory(TempDir.createTempDir())
val outDirPath = outDir.canonicalPath
val argsWithOutDir = extraArgs + s" -d $outDirPath -cp $outDirPath"
for (code <- codes) {
val compiler = newCompilerWithoutVirtualOutdir(extraArgs = argsWithOutDir)
- new compiler.Run().compileSources(List(makeSourceFile(code, "unitTestSource.scala")))
- checkReport(compiler, allowMessage)
+ new compiler.global.Run().compileSources(List(makeSourceFile(code, "unitTestSource.scala")))
+ compiler.checkReport(allowMessage)
afterEach(outDir)
}
@@ -138,31 +179,11 @@ object CodeGenTools {
classfiles
}
- def compileClassesSeparately(codes: List[String], extraArgs: String = "", allowMessage: StoreReporter#Info => Boolean = _ => false, afterEach: AbstractFile => Unit = _ => ()) = {
- readAsmClasses(compileSeparately(codes, extraArgs, allowMessage, afterEach))
+ def compileClassesSeparately(codes: List[String], extraArgs: String = "", allowMessage: StoreReporter#Info => Boolean = _ => false, afterEach: AbstractFile => Unit = _ => ()): List[ClassNode] = {
+ readAsmClasses(compileToBytesSeparately(codes, extraArgs, allowMessage, afterEach))
}
- def readAsmClasses(classfiles: List[(String, Array[Byte])]) = {
- classfiles.map(p => AsmUtils.readClass(p._2)).sortBy(_.name)
- }
-
- def compileClasses(compiler: Global)(code: String, javaCode: List[(String, String)] = Nil, allowMessage: StoreReporter#Info => Boolean = _ => false): List[ClassNode] = {
- readAsmClasses(compile(compiler)(code, javaCode, allowMessage))
- }
-
- def compileMethods(compiler: Global)(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): List[MethodNode] = {
- compileClasses(compiler)(s"class C { $code }", allowMessage = allowMessage).head.methods.asScala.toList.filterNot(_.name == "<init>")
- }
-
- def singleMethodInstructions(compiler: Global)(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): List[Instruction] = {
- val List(m) = compileMethods(compiler)(code, allowMessage = allowMessage)
- instructionsFromMethod(m)
- }
-
- def singleMethod(compiler: Global)(code: String, allowMessage: StoreReporter#Info => Boolean = _ => false): Method = {
- val List(m) = compileMethods(compiler)(code, allowMessage = allowMessage)
- convertMethod(m)
- }
+ def readAsmClasses(classfiles: List[(String, Array[Byte])]) = classfiles.map(p => AsmUtils.readClass(p._2)).sortBy(_.name)
def assertSameCode(method: Method, expected: List[Instruction]): Unit = assertSameCode(method.instructions.dropNonOp, expected)
def assertSameCode(actual: List[Instruction], expected: List[Instruction]): Unit = {
@@ -212,23 +233,51 @@ object CodeGenTools {
assert(indy.isEmpty, indy)
}
- def getSingleMethod(classNode: ClassNode, name: String): Method =
- convertMethod(classNode.methods.asScala.toList.find(_.name == name).get)
+ def findClass(cs: List[ClassNode], name: String): ClassNode = {
+ val List(c) = cs.filter(_.name == name)
+ c
+ }
+
+ def getAsmMethods(c: ClassNode, p: String => Boolean): List[MethodNode] =
+ c.methods.iterator.asScala.filter(m => p(m.name)).toList.sortBy(_.name)
- def findAsmMethods(c: ClassNode, p: String => Boolean) = c.methods.iterator.asScala.filter(m => p(m.name)).toList.sortBy(_.name)
- def findAsmMethod(c: ClassNode, name: String) = findAsmMethods(c, _ == name).head
+ def getAsmMethods(c: ClassNode, name: String): List[MethodNode] =
+ getAsmMethods(c, _ == name)
+
+ def getAsmMethod(c: ClassNode, name: String): MethodNode = {
+ val List(m) = getAsmMethods(c, name)
+ m
+ }
+
+ def getMethods(c: ClassNode, name: String): List[Method] =
+ getAsmMethods(c, name).map(convertMethod)
+
+ def getMethod(c: ClassNode, name: String): Method =
+ convertMethod(getAsmMethod(c, name))
+
+ def getInstructions(c: ClassNode, name: String): List[Instruction] =
+ getMethod(c, name).instructions
/**
* Instructions that match `query` when textified.
* If `query` starts with a `+`, the next instruction is returned.
*/
- def findInstr(method: MethodNode, query: String): List[AbstractInsnNode] = {
+ def findInstrs(method: MethodNode, query: String): List[AbstractInsnNode] = {
val useNext = query(0) == '+'
val instrPart = if (useNext) query.drop(1) else query
val insns = method.instructions.iterator.asScala.filter(i => textify(i) contains instrPart).toList
if (useNext) insns.map(_.getNext) else insns
}
+ /**
+ * Instruction that matches `query` when textified.
+ * If `query` starts with a `+`, the next instruction is returned.
+ */
+ def findInstr(method: MethodNode, query: String): AbstractInsnNode = {
+ val List(i) = findInstrs(method, query)
+ i
+ }
+
def assertHandlerLabelPostions(h: ExceptionHandler, instructions: List[Instruction], startIndex: Int, endIndex: Int, handlerIndex: Int): Unit = {
val insVec = instructions.toVector
assertTrue(h.start == insVec(startIndex) && h.end == insVec(endIndex) && h.handler == insVec(handlerIndex))
diff --git a/test/junit/scala/tools/testing/ClearAfterClass.java b/test/junit/scala/tools/testing/ClearAfterClass.java
index 232d459c4e..95e170ec13 100644
--- a/test/junit/scala/tools/testing/ClearAfterClass.java
+++ b/test/junit/scala/tools/testing/ClearAfterClass.java
@@ -1,20 +1,53 @@
package scala.tools.testing;
-import org.junit.AfterClass;
+import org.junit.ClassRule;
+import org.junit.rules.TestRule;
+import org.junit.runners.model.Statement;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
/**
- * Extend this class to use JUnit's @AfterClass. This annotation only works on static methods,
+ * Extend this class to use JUnit's @ClassRule. This annotation only works on static methods,
* which cannot be written in Scala.
*
* Example: {@link scala.tools.nsc.backend.jvm.opt.InlinerTest}
*/
public class ClearAfterClass {
- public static interface Clearable {
- void clear();
+ private static Map<Class<?>, Map<String, Object>> cache = new ConcurrentHashMap<>();
+
+ @ClassRule
+ public static TestRule clearClassCache() {
+ return (statement, desc) -> new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ ConcurrentHashMap<String, Object> perClassCache = new ConcurrentHashMap<>();
+ cache.put(desc.getTestClass(), perClassCache);
+ try {
+ statement.evaluate();
+ } finally {
+ perClassCache.values().forEach(ClearAfterClass::closeIfClosable);
+ cache.remove(desc.getTestClass());
+ }
+ }
+ };
}
- public static Clearable stateToClear;
+ private static void closeIfClosable(Object o) {
+ if (o instanceof Closeable) {
+ try {
+ ((Closeable) o).close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+
+ public <T> T cached(String key, scala.Function0<T> t) {
+ Map<String, Object> perClassCache = cache.get(getClass());
+ return (T) perClassCache.computeIfAbsent(key, s -> t.apply());
+ }
- @AfterClass
- public static void clearState() { stateToClear.clear(); }
}
diff --git a/test/junit/scala/tools/testing/RunTesting.scala b/test/junit/scala/tools/testing/RunTesting.scala
new file mode 100644
index 0000000000..1320db4230
--- /dev/null
+++ b/test/junit/scala/tools/testing/RunTesting.scala
@@ -0,0 +1,17 @@
+package scala.tools.testing
+
+import scala.reflect.runtime._
+import scala.tools.reflect.ToolBox
+
+trait RunTesting extends ClearAfterClass {
+ def compilerArgs = "" // to be overridden
+ val runner = cached("toolbox", () => Runner.make(compilerArgs))
+}
+
+class Runner(val toolBox: ToolBox[universe.type]) {
+ def run[T](code: String): T = toolBox.eval(toolBox.parse(code)).asInstanceOf[T]
+}
+
+object Runner {
+ def make(compilerArgs: String) = new Runner(universe.runtimeMirror(getClass.getClassLoader).mkToolBox(options = compilerArgs))
+}