summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTING.md28
-rw-r--r--README.md380
-rw-r--r--build.sbt80
-rw-r--r--build.xml2
-rw-r--r--project/GenerateAnyVals.scala12
-rw-r--r--project/Osgi.scala9
-rw-r--r--project/Quiet.scala33
-rw-r--r--project/plugins.sbt2
-rwxr-xr-xscripts/jobs/integrate/windows18
-rw-r--r--spec/02-identifiers-names-and-scopes.md91
-rw-r--r--src/compiler/scala/reflect/reify/codegen/GenUtils.scala2
-rw-r--r--src/compiler/scala/reflect/reify/phases/Reify.scala6
-rw-r--r--src/compiler/scala/reflect/reify/utils/NodePrinters.scala2
-rw-r--r--src/compiler/scala/tools/cmd/Property.scala4
-rw-r--r--src/compiler/scala/tools/nsc/GenericRunnerSettings.scala4
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala157
-rw-r--r--src/compiler/scala/tools/nsc/ScriptRunner.scala9
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/JavaPlatform.scala38
-rw-r--r--src/compiler/scala/tools/nsc/backend/Platform.scala10
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala3
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala377
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala32
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala32
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala23
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala5
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala6
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala3
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerImpl.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala150
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala10
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala39
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/CopyProp.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/InlineInfoAttribute.scala44
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala3
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala2
-rw-r--r--src/compiler/scala/tools/nsc/classpath/AggregateClassPath.scala (renamed from src/compiler/scala/tools/nsc/classpath/AggregateFlatClassPath.scala)68
-rw-r--r--src/compiler/scala/tools/nsc/classpath/ClassPath.scala60
-rw-r--r--src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala63
-rw-r--r--src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala (renamed from src/compiler/scala/tools/nsc/classpath/DirectoryFlatClassPath.scala)23
-rw-r--r--src/compiler/scala/tools/nsc/classpath/FlatClassPath.scala98
-rw-r--r--src/compiler/scala/tools/nsc/classpath/FlatClassPathFactory.scala44
-rw-r--r--src/compiler/scala/tools/nsc/classpath/PackageNameUtils.scala2
-rw-r--r--src/compiler/scala/tools/nsc/classpath/VirtualDirectoryClassPath.scala (renamed from src/compiler/scala/tools/nsc/classpath/VirtualDirectoryFlatClassPath.scala)5
-rw-r--r--src/compiler/scala/tools/nsc/classpath/ZipAndJarFileLookupFactory.scala45
-rw-r--r--src/compiler/scala/tools/nsc/classpath/ZipArchiveFileLookup.scala9
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala6
-rw-r--r--src/compiler/scala/tools/nsc/settings/Warnings.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala51
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala20
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala34
-rw-r--r--src/compiler/scala/tools/nsc/transform/LazyVals.scala14
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala45
-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/ConstantFolder.scala18
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala10
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala16
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala15
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala65
-rw-r--r--src/compiler/scala/tools/nsc/util/ClassFileLookup.scala78
-rw-r--r--src/compiler/scala/tools/nsc/util/ClassPath.scala374
-rw-r--r--src/compiler/scala/tools/reflect/ReflectMain.scala4
-rw-r--r--src/compiler/scala/tools/util/PathResolver.scala67
-rw-r--r--src/eclipse/README.md25
-rw-r--r--src/eclipse/interactive/.classpath2
-rw-r--r--src/eclipse/partest/.classpath8
-rw-r--r--src/eclipse/reflect/.classpath1
-rw-r--r--src/eclipse/repl/.classpath6
-rw-r--r--src/eclipse/scala-compiler/.classpath3
-rw-r--r--src/eclipse/scaladoc/.classpath9
-rw-r--r--src/eclipse/test-junit/.classpath6
-rwxr-xr-xsrc/eclipse/update-workspace.sh72
-rw-r--r--src/intellij/README.md64
-rw-r--r--src/intellij/scala.ipr.SAMPLE12
-rw-r--r--src/library/rootdoc.txt2
-rw-r--r--src/library/scala/Console.scala146
-rw-r--r--src/library/scala/Product.scala2
-rw-r--r--src/library/scala/Unit.scala4
-rw-r--r--src/library/scala/collection/JavaConversions.scala20
-rw-r--r--src/library/scala/collection/JavaConverters.scala62
-rw-r--r--src/library/scala/collection/concurrent/TrieMap.scala4
-rw-r--r--src/library/scala/collection/convert/AsJavaConverters.scala262
-rw-r--r--src/library/scala/collection/convert/AsScalaConverters.scala207
-rw-r--r--src/library/scala/collection/convert/DecorateAsJava.scala250
-rw-r--r--src/library/scala/collection/convert/DecorateAsScala.scala155
-rw-r--r--src/library/scala/collection/convert/Decorators.scala10
-rw-r--r--src/library/scala/collection/convert/ImplicitConversions.scala125
-rw-r--r--src/library/scala/collection/convert/WrapAsJava.scala25
-rw-r--r--src/library/scala/collection/convert/WrapAsScala.scala23
-rw-r--r--src/library/scala/collection/convert/Wrappers.scala5
-rw-r--r--src/library/scala/collection/convert/package.scala9
-rw-r--r--src/library/scala/collection/immutable/BitSet.scala12
-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/collection/mutable/ArrayOps.scala9
-rw-r--r--src/library/scala/collection/mutable/PriorityQueue.scala128
-rw-r--r--src/library/scala/collection/mutable/WrappedArray.scala9
-rw-r--r--src/library/scala/collection/mutable/WrappedArrayBuilder.scala3
-rw-r--r--src/library/scala/collection/package.scala8
-rw-r--r--src/library/scala/concurrent/Future.scala163
-rw-r--r--src/library/scala/io/AnsiColor.scala155
-rw-r--r--src/library/scala/reflect/ClassTag.scala5
-rw-r--r--src/library/scala/runtime/ArrayRuntime.java26
-rw-r--r--src/library/scala/runtime/Boxed.scala12
-rw-r--r--src/library/scala/runtime/BoxesRunTime.java64
-rw-r--r--src/library/scala/runtime/ScalaRunTime.scala123
-rw-r--r--src/library/scala/runtime/Statics.java54
-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/library/scala/sys/process/package.scala4
-rw-r--r--src/library/scala/util/control/Exception.scala190
-rw-r--r--src/library/scala/util/matching/Regex.scala29
-rw-r--r--src/partest-extras/scala/tools/partest/BytecodeTest.scala18
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala1
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala5
-rw-r--r--src/reflect/scala/reflect/internal/transform/Erasure.scala5
-rw-r--r--src/reflect/scala/reflect/io/ZipArchive.scala4
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala12
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverseForce.scala1
-rw-r--r--src/repl-jline/scala/tools/nsc/interpreter/jline/JLineReader.scala26
-rw-r--r--src/repl/scala/tools/nsc/interpreter/IMain.scala217
-rw-r--r--src/repl/scala/tools/nsc/interpreter/Imports.scala35
-rw-r--r--src/repl/scala/tools/nsc/interpreter/PresentationCompilation.scala25
-rw-r--r--src/repl/scala/tools/nsc/interpreter/ReplStrings.scala16
-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/base/CommentFactoryBase.scala2
-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--src/scalap/scala/tools/scalap/Main.scala30
-rw-r--r--test/disabled/presentation/akka/src/akka/actor/ActorRegistry.scala4
-rw-r--r--test/disabled/presentation/akka/src/akka/actor/Scheduler.scala2
-rw-r--r--test/disabled/presentation/akka/src/akka/japi/JavaAPI.scala2
-rw-r--r--test/disabled/presentation/akka/src/akka/routing/Iterators.scala2
-rw-r--r--test/disabled/presentation/akka/src/akka/routing/Listeners.scala2
-rw-r--r--test/files/jvm/interpreter.check2
-rw-r--r--test/files/jvm/scala-concurrent-tck.check2
-rw-r--r--test/files/jvm/scala-concurrent-tck.scala31
-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/nowarnDefaultJunitMethods.check6
-rw-r--r--test/files/neg/nowarnDefaultJunitMethods.flags1
-rw-r--r--test/files/neg/nowarnDefaultJunitMethods/C_1.scala5
-rw-r--r--test/files/neg/nowarnDefaultJunitMethods/Test.java3
-rw-r--r--test/files/neg/saferJavaConversions.scala6
-rw-r--r--test/files/neg/t4460a.check2
-rw-r--r--test/files/neg/t4460b.check2
-rw-r--r--test/files/neg/t4749.check2
-rw-r--r--test/files/neg/t5148.check16
-rw-r--r--test/files/neg/t5580b.scala2
-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/neg/t9684.check9
-rw-r--r--test/files/neg/t9684.flags1
-rw-r--r--test/files/neg/t9684.scala9
-rw-r--r--test/files/neg/t9684b.check7
-rw-r--r--test/files/neg/t9684b.scala14
-rw-r--r--test/files/pos/arrays2.scala2
-rw-r--r--test/files/pos/constant-warning.check4
-rw-r--r--test/files/pos/constant-warning.flags1
-rw-r--r--test/files/pos/constant-warning.scala3
-rw-r--r--test/files/pos/javaConversions-2.10-ambiguity.scala4
-rw-r--r--test/files/pos/javaConversions-2.10-regression.scala6
-rw-r--r--test/files/pos/t2293.scala4
-rw-r--r--test/files/pos/t2956/t2956.scala4
-rw-r--r--test/files/pos/t3688.scala4
-rw-r--r--test/files/pos/t5148.scala (renamed from test/files/neg/t5148.scala)0
-rw-r--r--test/files/pos/t5183.scala34
-rw-r--r--test/files/pos/t5644/BoxesRunTime.java4
-rw-r--r--test/files/pos/t7088.scala8
-rw-r--r--test/files/pos/t9397.scala12
-rw-r--r--test/files/pos/t9665.scala7
-rw-r--r--test/files/presentation/ide-bug-1000531/src/CrashOnLoad.scala2
-rw-r--r--test/files/run/concurrent-map-conversions.scala15
-rw-r--r--test/files/run/equality.scala2
-rw-r--r--test/files/run/hashCodeStatics.scala (renamed from test/files/run/hashCodeBoxesRunTime.scala)10
-rw-r--r--test/files/run/map_java_conversions.scala11
-rw-r--r--test/files/run/mixin-signatures.check21
-rw-r--r--test/files/run/noInlineUnknownIndy/Test.scala2
-rw-r--r--test/files/run/reify_printf.scala1
-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-no-uescape.check5
-rw-r--r--test/files/run/repl-no-uescape.scala31
-rwxr-xr-xtest/files/run/repl-paste-6.check17
-rw-r--r--test/files/run/repl-paste-6.scala23
-rw-r--r--test/files/run/repl-serialization.scala2
-rw-r--r--test/files/run/t1500.scala2
-rw-r--r--test/files/run/t2106.check2
-rw-r--r--test/files/run/t2250.scala2
-rw-r--r--test/files/run/t2813.2.scala2
-rw-r--r--test/files/run/t3822.scala19
-rw-r--r--test/files/run/t5463.scala21
-rw-r--r--test/files/run/t5652.check1
-rw-r--r--test/files/run/t5880.scala5
-rw-r--r--test/files/run/t6198.scala7
-rw-r--r--test/files/run/t6502.scala18
-rw-r--r--test/files/run/t6554.scala12
-rw-r--r--test/files/run/t7269.scala2
-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/t7932.check5
-rw-r--r--test/files/run/t7932.scala25
-rw-r--r--test/files/run/t7933.check2
-rw-r--r--test/files/run/t7933.scala11
-rw-r--r--test/files/run/t7974/Test.scala2
-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/t9516.scala52
-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/files/run/various-flat-classpath-types.scala9
-rw-r--r--test/files/scalacheck/MutablePriorityQueue.scala102
-rw-r--r--test/instrumented/library/scala/runtime/BoxesRunTime.java4
-rw-r--r--test/instrumented/library/scala/runtime/ScalaRunTime.scala118
-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/collection/mutable/PriorityQueueTest.scala7
-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)55
-rw-r--r--test/junit/scala/reflect/internal/PrintersTest.scala26
-rw-r--r--test/junit/scala/runtime/ScalaRunTimeTest.scala65
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala40
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala (renamed from test/junit/scala/issues/BytecodeTest.scala)140
-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.scala70
-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.scala46
-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.scala68
-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.scala401
-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.scala47
-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/classpath/AggregateClassPathTest.scala (renamed from test/junit/scala/tools/nsc/classpath/AggregateFlatClassPathTest.scala)27
-rw-r--r--test/junit/scala/tools/nsc/classpath/PathResolverBaseTest.scala (renamed from test/junit/scala/tools/nsc/classpath/FlatClassPathResolverTest.scala)59
-rw-r--r--test/junit/scala/tools/nsc/interpreter/ScriptedTest.scala83
-rw-r--r--test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala27
-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/nsc/util/ClassPathImplComparator.scala143
-rw-r--r--test/junit/scala/tools/testing/BytecodeTesting.scala (renamed from test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala)249
-rw-r--r--test/junit/scala/tools/testing/ClearAfterClass.java47
-rw-r--r--test/junit/scala/tools/testing/RunTesting.scala17
-rw-r--r--test/junit/scala/util/matching/RegexTest.scala64
-rw-r--r--test/pending/run/origins.check (renamed from test/files/run/origins.check)0
-rw-r--r--test/pending/run/origins.flags (renamed from test/files/run/origins.flags)0
-rw-r--r--test/pending/run/origins.scala (renamed from test/files/run/origins.scala)0
-rw-r--r--test/scaladoc/run/t9752.check5
-rw-r--r--test/scaladoc/run/t9752.scala28
-rw-r--r--versions.properties4
320 files changed, 6796 insertions, 5226 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 4ce58459a7..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`.
-
-### 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 4962e4e41c..d592b86aff 100644
--- a/build.sbt
+++ b/build.sbt
@@ -84,7 +84,7 @@ lazy val publishSettings : Seq[Setting[_]] = Seq(
val mappings = artifacts.toSeq.map { case (a, f) =>
val typeSuffix = a.`type` match {
case "pom" => "-pom.xml"
- case "bundle" | "jar" => ".jar"
+ case "jar" => ".jar"
case "doc" => "-docs.jar"
case tpe => s"-$tpe.${a.extension}"
}
@@ -99,6 +99,8 @@ lazy val publishSettings : Seq[Setting[_]] = Seq(
if (file.exists) List(Credentials(file))
else Nil
},
+ // Add a "default" Ivy configuration because sbt expects the Scala distribution to have one:
+ ivyConfigurations += Configuration("default", "Default", true, List(Configurations.Runtime), true),
publishMavenStyle := true
)
@@ -206,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
@@ -236,8 +240,8 @@ def fixPom(extra: (String, scala.xml.Node)*): Setting[_] = {
) ++ extra) }
}
-/** Remove unwanted dependencies from the POM. */
-def removePomDependencies(deps: (String, String)*): Setting[_] = {
+/** Remove unwanted dependencies from the POM and ivy.xml. */
+def removePomDependencies(deps: (String, String)*): Seq[Setting[_]] = Seq(
pomPostProcess := { n =>
val n2 = pomPostProcess.value.apply(n)
import scala.xml._
@@ -252,14 +256,40 @@ def removePomDependencies(deps: (String, String)*): Setting[_] = {
case n => Seq(n)
}
})).transform(Seq(n2)).head
+ },
+ deliverLocal := {
+ import scala.xml._
+ import scala.xml.transform._
+ val f = deliverLocal.value
+ val e = (new RuleTransformer(new RewriteRule {
+ override def transform(node: Node) = node match {
+ case e: Elem if e.label == "dependency" && {
+ val org = e.attribute("org").getOrElse("").toString
+ val name = e.attribute("name").getOrElse("").toString
+ deps.exists { case (g, a) =>
+ org == g && (name == a || name == (a + "_" + scalaBinaryVersion.value))
+ }
+ } => Seq.empty
+ case n => Seq(n)
+ }
+ })).transform(Seq(XML.loadFile(f))).head
+ XML.save(f.getAbsolutePath, e, xmlDecl = true)
+ f
}
-}
+)
val disableDocs = Seq[Setting[_]](
sources in (Compile, doc) := Seq.empty,
publishArtifact in (Compile, packageDoc) := false
)
+val disablePublishing = Seq[Setting[_]](
+ publishArtifact := false,
+ // The above is enough for Maven repos but it doesn't prevent publishing of ivy.xml files
+ publish := {},
+ publishLocal := {}
+)
+
lazy val setJarLocation: Setting[_] =
artifactPath in packageBin in Compile := {
// two lines below are copied over from sbt's sources:
@@ -397,43 +427,44 @@ lazy val compiler = configureAsSubproject(project)
"/project/description" -> <description>Compiler for the Scala Programming Language</description>,
"/project/packaging" -> <packaging>jar</packaging>
),
- apiURL := None,
- removePomDependencies(
- ("org.apache.ant", "ant"),
- ("org.scala-lang.modules", "scala-asm")
- )
+ apiURL := None
)
+ .settings(removePomDependencies(
+ ("org.apache.ant", "ant"),
+ ("org.scala-lang.modules", "scala-asm")
+ ): _*)
.dependsOn(library, reflect)
lazy val interactive = configureAsSubproject(project)
.settings(disableDocs: _*)
+ .settings(disablePublishing: _*)
.settings(
name := "scala-compiler-interactive",
- description := "Scala Interactive Compiler",
- publishArtifact := false
+ description := "Scala Interactive Compiler"
)
.dependsOn(compiler)
lazy val repl = configureAsSubproject(project)
.settings(disableDocs: _*)
+ .settings(disablePublishing: _*)
.settings(
connectInput in run := true,
- publishArtifact := false,
run <<= (run in Compile).partialInput(" -usejavacp") // Automatically add this so that `repl/run` works without additional arguments.
)
.dependsOn(compiler, interactive)
lazy val replJline = configureAsSubproject(Project("repl-jline", file(".") / "src" / "repl-jline"))
.settings(disableDocs: _*)
+ .settings(disablePublishing: _*)
.settings(
libraryDependencies += jlineDep,
- name := "scala-repl-jline",
- publishArtifact := false
+ name := "scala-repl-jline"
)
.dependsOn(repl)
lazy val replJlineEmbedded = Project("repl-jline-embedded", file(".") / "target" / "repl-jline-embedded-src-dummy")
.settings(scalaSubprojectSettings: _*)
+ .settings(disablePublishing: _*)
.settings(
name := "scala-repl-jline-embedded",
// There is nothing to compile for this project. Instead we use the compile task to create
@@ -464,19 +495,19 @@ lazy val replJlineEmbedded = Project("repl-jline-embedded", file(".") / "target"
val outdir = (classDirectory in Compile).value
JarJar(inputs, outdir, config)
}),
- publishArtifact := false,
connectInput in run := true
+
)
.dependsOn(replJline)
lazy val scaladoc = configureAsSubproject(project)
.settings(disableDocs: _*)
+ .settings(disablePublishing: _*)
.settings(
name := "scala-compiler-doc",
description := "Scala Documentation Generator",
libraryDependencies ++= Seq(scalaXmlDep, scalaParserCombinatorsDep, partestDep),
- publishArtifact := false,
- 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)
@@ -497,10 +528,10 @@ lazy val partestExtras = configureAsSubproject(Project("partest-extras", file(".
.dependsOn(replJlineEmbedded)
.settings(clearSourceAndResourceDirectories: _*)
.settings(disableDocs: _*)
+ .settings(disablePublishing: _*)
.settings(
name := "scala-partest-extras",
description := "Scala Compiler Testing Tool (compiler-specific extras)",
- publishArtifact := false,
libraryDependencies += partestDep,
unmanagedSourceDirectories in Compile := List(baseDirectory.value)
)
@@ -510,8 +541,8 @@ lazy val junit = project.in(file("test") / "junit")
.settings(clearSourceAndResourceDirectories: _*)
.settings(commonSettings: _*)
.settings(disableDocs: _*)
+ .settings(disablePublishing: _*)
.settings(
- publishArtifact := false,
fork in Test := true,
libraryDependencies ++= Seq(junitDep, junitIntefaceDep),
testOptions += Tests.Argument(TestFrameworks.JUnit, "-a", "-v"),
@@ -543,9 +574,9 @@ lazy val test = project
.configs(IntegrationTest)
.settings(commonSettings: _*)
.settings(disableDocs: _*)
+ .settings(disablePublishing: _*)
.settings(Defaults.itSettings: _*)
.settings(
- publishArtifact := false,
libraryDependencies ++= Seq(asmDep, partestDep, scalaXmlDep, scalacheckDep),
unmanagedBase in IntegrationTest := baseDirectory.value / "files" / "lib",
unmanagedJars in IntegrationTest <+= (unmanagedBase) (j => Attributed.blank(j)) map(identity),
@@ -572,8 +603,8 @@ lazy val test = project
lazy val manual = configureAsSubproject(project)
.settings(disableDocs: _*)
+ .settings(disablePublishing: _*)
.settings(
- publishArtifact := false,
libraryDependencies ++= Seq(scalaXmlDep, antDep),
classDirectory in Compile := (target in Compile).value / "classes"
)
@@ -643,9 +674,9 @@ lazy val scalaDist = Project("scala-dist", file(".") / "target" / "scala-dist-di
lazy val root = (project in file("."))
.settings(disableDocs: _*)
+ .settings(disablePublishing: _*)
.settings(generateBuildCharacterFileSettings: _*)
.settings(
- publishArtifact := false,
publish := {},
publishLocal := {},
commands ++= ScriptCommands.all,
@@ -658,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/GenerateAnyVals.scala b/project/GenerateAnyVals.scala
index 921982aeec..84454cb0ed 100644
--- a/project/GenerateAnyVals.scala
+++ b/project/GenerateAnyVals.scala
@@ -225,7 +225,9 @@ import scala.language.implicitConversions"""
"@unboxRunTimeDoc@" -> """
* Runtime implementation determined by `scala.runtime.BoxesRunTime.unboxTo%s`. See [[https://github.com/scala/scala src/library/scala/runtime/BoxesRunTime.java]].
*""".format(name),
- "@unboxDoc@" -> "the %s resulting from calling %sValue() on `x`".format(name, lcname)
+ "@unboxDoc@" -> "the %s resulting from calling %sValue() on `x`".format(name, lcname),
+ "@boxImpl@" -> "???",
+ "@unboxImpl@" -> "???"
)
def interpolations = Map(
"@name@" -> name,
@@ -296,7 +298,7 @@ package scala
* @param x the @name@ to be boxed
* @return a @boxed@ offering `x` as its underlying value.
*/
-def box(x: @name@): @boxed@ = ???
+def box(x: @name@): @boxed@ = @boxImpl@
/** Transform a boxed type into a value type. Note that this
* method is not typesafe: it accepts any Object, but will throw
@@ -306,7 +308,7 @@ def box(x: @name@): @boxed@ = ???
* @throws ClassCastException if the argument is not a @boxed@
* @return @unboxDoc@
*/
-def unbox(x: java.lang.Object): @name@ = ???
+def unbox(x: java.lang.Object): @name@ = @unboxImpl@
/** The String representation of the scala.@name@ companion object. */
override def toString = "object scala.@name@"
@@ -458,7 +460,9 @@ override def getClass(): Class[Boolean] = ???
override def boxUnboxInterpolations = Map(
"@boxRunTimeDoc@" -> "",
"@unboxRunTimeDoc@" -> "",
- "@unboxDoc@" -> "the Unit value ()"
+ "@unboxDoc@" -> "the Unit value ()",
+ "@boxImpl@" -> "scala.runtime.BoxedUnit.UNIT",
+ "@unboxImpl@" -> "x.asInstanceOf[scala.runtime.BoxedUnit]"
)
}
diff --git a/project/Osgi.scala b/project/Osgi.scala
index 4676119076..36803c0e44 100644
--- a/project/Osgi.scala
+++ b/project/Osgi.scala
@@ -3,7 +3,7 @@ import aQute.bnd.osgi.Constants._
import java.util.Properties
import sbt._
import sbt.Keys._
-import scala.collection.JavaConversions._
+import collection.JavaConverters._
import VersionUtil.versionProperties
/** OSGi packaging for the Scala build, distilled from sbt-osgi. We do not use sbt-osgi because it
@@ -40,7 +40,6 @@ object Osgi {
},
packagedArtifact in (Compile, packageBin) <<= (artifact in (Compile, packageBin), bundle).identityMap,
// Also create OSGi source bundles:
- artifact in (Compile, packageBin) ~= (_.copy(`type` = "bundle")),
packageOptions in (Compile, packageSrc) += Package.ManifestAttributes(
"Bundle-Name" -> (description.value + " Sources"),
"Bundle-SymbolicName" -> (bundleSymbolicName.value + ".source"),
@@ -57,12 +56,12 @@ object Osgi {
headers foreach { case (k, v) => builder.setProperty(k, v) }
val includeRes = resourceDirectories.filter(_.exists).map(_.getAbsolutePath).mkString(",")
if(!includeRes.isEmpty) builder.setProperty(INCLUDERESOURCE, includeRes)
- builder.getProperties.foreach { case (k, v) => log.debug(s"bnd: $k: $v") }
+ builder.getProperties.asScala.foreach { case (k, v) => log.debug(s"bnd: $k: $v") }
// builder.build is not thread-safe because it uses a static SimpleDateFormat. This ensures
// that all calls to builder.build are serialized.
val jar = synchronized { builder.build }
- builder.getWarnings.foreach(s => log.warn(s"bnd: $s"))
- builder.getErrors.foreach(s => log.error(s"bnd: $s"))
+ builder.getWarnings.asScala.foreach(s => log.warn(s"bnd: $s"))
+ builder.getErrors.asScala.foreach(s => log.error(s"bnd: $s"))
IO.createDirectory(artifactPath.getParentFile)
jar.write(artifactPath)
artifactPath
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/scripts/jobs/integrate/windows b/scripts/jobs/integrate/windows
index be68a826f7..ba48c5bc25 100755
--- a/scripts/jobs/integrate/windows
+++ b/scripts/jobs/integrate/windows
@@ -1,15 +1,15 @@
-#!/bin/bash -x
+#!/bin/bash
./pull-binary-libs.sh
export ANT_OPTS="-Dfile.encoding=UTF-8 -server -XX:+AggressiveOpts -XX:+UseParNewGC -Xmx2G -Xss1M -XX:MaxPermSize=512M -XX:ReservedCodeCacheSize=128M"
-# TODO: don't hardcode this path, which is just where we currently have
-# ant manually installed on jenkins-worker-windows-publish.
-PATH=/cygdrive/c/apache-ant-1.9.6/bin:$PATH
+# TODO: don't hardcode these paths -- should be in scala/scala-jenkins-infra, passed in through env vars from jenkins
+export PATH='/cygdrive/c/Program Files/Java/jdk1.8.0_92/bin:/cygdrive/c/apache-ant-1.9.6/bin:/cygdrive/c/Program Files (x86)/Git-2.5.3/Cmd:/bin:/usr/bin:'
+export JAVA_HOME='C:/Program Files/Java/jdk1.8.0_92'
-ant \
- -Dstarr.version=2.11.7 \
- -Dscalac.args.optimise=-optimise \
- -Dlocker.skip=1 \
- test
+java -version
+javac -version
+ant -version
+
+ant test-opt
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/reflect/reify/codegen/GenUtils.scala b/src/compiler/scala/reflect/reify/codegen/GenUtils.scala
index b5b0f93750..242e5d60b3 100644
--- a/src/compiler/scala/reflect/reify/codegen/GenUtils.scala
+++ b/src/compiler/scala/reflect/reify/codegen/GenUtils.scala
@@ -55,7 +55,7 @@ trait GenUtils {
mirrorCall(TermName("" + prefix), args: _*)
def scalaFactoryCall(name: TermName, args: Tree*): Tree =
- call(s"scala.$name.apply", args: _*)
+ call(s"_root_.scala.$name.apply", args: _*)
def scalaFactoryCall(name: String, args: Tree*): Tree =
scalaFactoryCall(TermName(name), args: _*)
diff --git a/src/compiler/scala/reflect/reify/phases/Reify.scala b/src/compiler/scala/reflect/reify/phases/Reify.scala
index 143424dac5..93f6f99d81 100644
--- a/src/compiler/scala/reflect/reify/phases/Reify.scala
+++ b/src/compiler/scala/reflect/reify/phases/Reify.scala
@@ -1,7 +1,6 @@
package scala.reflect.reify
package phases
-import scala.runtime.ScalaRunTime.isAnyVal
import scala.reflect.reify.codegen._
trait Reify extends GenSymbols
@@ -57,4 +56,9 @@ trait Reify extends GenSymbols
case _ =>
throw new Error("reifee %s of type %s is not supported".format(reifee, reifee.getClass))
})
+
+ private def isAnyVal(x: Any) = x match {
+ case _: Byte | _: Short | _: Char | _: Int | _: Long | _: Float | _: Double | _: Boolean | _: Unit => true
+ case _ => false
+ }
}
diff --git a/src/compiler/scala/reflect/reify/utils/NodePrinters.scala b/src/compiler/scala/reflect/reify/utils/NodePrinters.scala
index 3b91d28360..a5c4c7e0a3 100644
--- a/src/compiler/scala/reflect/reify/utils/NodePrinters.scala
+++ b/src/compiler/scala/reflect/reify/utils/NodePrinters.scala
@@ -28,7 +28,7 @@ trait NodePrinters {
var s = line substring 2
s = s.replace(nme.UNIVERSE_PREFIX.toString, "")
s = s.replace(".apply", "")
- s = "([^\"])scala\\.collection\\.immutable\\.".r.replaceAllIn(s, "$1")
+ s = "([^\"])(_root_\\.)?scala\\.collection\\.immutable\\.".r.replaceAllIn(s, "$1")
s = "List\\[List\\[.*?\\].*?\\]".r.replaceAllIn(s, "List")
s = "List\\[.*?\\]".r.replaceAllIn(s, "List")
s = s.replace("immutable.this.Nil", "List()")
diff --git a/src/compiler/scala/tools/cmd/Property.scala b/src/compiler/scala/tools/cmd/Property.scala
index e6262a7e40..18bedd6f7e 100644
--- a/src/compiler/scala/tools/cmd/Property.scala
+++ b/src/compiler/scala/tools/cmd/Property.scala
@@ -65,8 +65,8 @@ trait Property extends Reference {
propertiesToOptions(loadProperties(file))
def propertiesToOptions(props: java.util.Properties): List[String] = {
- import scala.collection.JavaConversions._
- propertiesToOptions(props.toList)
+ import scala.collection.JavaConverters._
+ propertiesToOptions(props.asScala.toList)
}
def propertiesToOptions(props: List[(String, String)]) = props flatMap propMapper
}
diff --git a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala
index e99cce9186..c82ed68da8 100644
--- a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala
+++ b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala
@@ -6,10 +6,10 @@
package scala.tools.nsc
import java.net.URL
-import scala.tools.util.PathResolverFactory
+import scala.tools.util.PathResolver
class GenericRunnerSettings(error: String => Unit) extends Settings(error) {
- lazy val classpathURLs: Seq[URL] = PathResolverFactory.create(this).resultAsURLs
+ lazy val classpathURLs: Seq[URL] = new PathResolver(this).resultAsURLs
val howtorun =
ChoiceSetting(
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 847c4cb2d1..7417d9c09d 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -13,7 +13,7 @@ import java.nio.charset.{Charset, CharsetDecoder, IllegalCharsetNameException, U
import scala.collection.{immutable, mutable}
import io.{AbstractFile, Path, SourceReader}
import reporters.Reporter
-import util.{ClassFileLookup, ClassPath, StatisticsInfo, returning}
+import util.{ClassPath, StatisticsInfo, returning}
import scala.reflect.ClassTag
import scala.reflect.internal.util.{BatchSourceFile, NoSourceFile, ScalaClassLoader, ScriptSourceFile, SourceFile}
import scala.reflect.internal.pickling.PickleBuffer
@@ -30,7 +30,6 @@ import backend.jvm.GenBCode
import scala.language.postfixOps
import scala.tools.nsc.ast.{TreeGen => AstTreeGen}
import scala.tools.nsc.classpath._
-import scala.tools.nsc.settings.ClassPathRepresentationType
class Global(var currentSettings: Settings, var reporter: Reporter)
extends SymbolTable
@@ -54,12 +53,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
class GlobalMirror extends Roots(NoSymbol) {
val universe: self.type = self
- def rootLoader: LazyType = {
- settings.YclasspathImpl.value match {
- case ClassPathRepresentationType.Flat => new loaders.PackageLoaderUsingFlatClassPath(FlatClassPath.RootPackage, flatClassPath)
- case ClassPathRepresentationType.Recursive => new loaders.PackageLoader(recursiveClassPath)
- }
- }
+ def rootLoader: LazyType = new loaders.PackageLoader(ClassPath.RootPackage, classPath)
override def toString = "compiler mirror"
}
implicit val MirrorTag: ClassTag[Mirror] = ClassTag[Mirror](classOf[GlobalMirror])
@@ -102,14 +96,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
type ThisPlatform = JavaPlatform { val global: Global.this.type }
lazy val platform: ThisPlatform = new GlobalPlatform
- def classPath: ClassFileLookup[AbstractFile] = settings.YclasspathImpl.value match {
- case ClassPathRepresentationType.Flat => flatClassPath
- case ClassPathRepresentationType.Recursive => recursiveClassPath
- }
-
- private def recursiveClassPath: ClassPath[AbstractFile] = platform.classPath
-
- private def flatClassPath: FlatClassPath = platform.flatClassPath
+ def classPath: ClassPath = platform.classPath
// sub-components --------------------------------------------------
@@ -394,15 +381,18 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
if (settings.debug && (settings.verbose || currentRun.size < 5))
inform("[running phase " + name + " on " + unit + "]")
+ if (!cancelled(unit)) {
+ currentRun.informUnitStarting(this, unit)
+ try withCurrentUnitNoLog(unit)(task)
+ finally currentRun.advanceUnit()
+ }
+ }
+ final def withCurrentUnitNoLog(unit: CompilationUnit)(task: => Unit) {
val unit0 = currentUnit
try {
currentRun.currentUnit = unit
- if (!cancelled(unit)) {
- currentRun.informUnitStarting(this, unit)
- task
- }
- currentRun.advanceUnit()
+ task
} finally {
//assert(currentUnit == unit)
currentRun.currentUnit = unit0
@@ -768,17 +758,10 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
/** Extend classpath of `platform` and rescan updated packages. */
def extendCompilerClassPath(urls: URL*): Unit = {
- if (settings.YclasspathImpl.value == ClassPathRepresentationType.Flat) {
- val urlClasspaths = urls.map(u => FlatClassPathFactory.newClassPath(AbstractFile.getURL(u), settings))
- val newClassPath = AggregateFlatClassPath.createAggregate(platform.flatClassPath +: urlClasspaths : _*)
- platform.currentFlatClassPath = Some(newClassPath)
- invalidateClassPathEntries(urls.map(_.getPath): _*)
- } else {
- val newClassPath = platform.classPath.mergeUrlsIntoClassPath(urls: _*)
- platform.currentClassPath = Some(newClassPath)
- // Reload all specified jars into this compiler instance
- invalidateClassPathEntries(urls.map(_.getPath): _*)
- }
+ val urlClasspaths = urls.map(u => ClassPathFactory.newClassPath(AbstractFile.getURL(u), settings))
+ val newClassPath = AggregateClassPath.createAggregate(platform.classPath +: urlClasspaths : _*)
+ platform.currentClassPath = Some(newClassPath)
+ invalidateClassPathEntries(urls.map(_.getPath): _*)
}
// ------------ Invalidations ---------------------------------
@@ -810,28 +793,26 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
* entries on the classpath.
*/
def invalidateClassPathEntries(paths: String*): Unit = {
- implicit object ClassPathOrdering extends Ordering[ClassFileLookup[AbstractFile]] {
- def compare(a:ClassFileLookup[AbstractFile], b:ClassFileLookup[AbstractFile]) = a.asClassPathString compare b.asClassPathString
+ implicit object ClassPathOrdering extends Ordering[ClassPath] {
+ def compare(a: ClassPath, b: ClassPath): Int = a.asClassPathString compareTo b.asClassPathString
}
val invalidated, failed = new mutable.ListBuffer[ClassSymbol]
- def assoc(path: String): Option[(ClassFileLookup[AbstractFile], ClassFileLookup[AbstractFile])] = {
- def origin(lookup: ClassFileLookup[AbstractFile]): Option[String] = lookup match {
- case cp: ClassPath[_] => cp.origin
+ def assoc(path: String): Option[(ClassPath, ClassPath)] = {
+ def origin(lookup: ClassPath): Option[String] = lookup match {
case cp: JFileDirectoryLookup[_] => Some(cp.dir.getPath)
case cp: ZipArchiveFileLookup[_] => Some(cp.zipFile.getPath)
case _ => None
}
- def entries(lookup: ClassFileLookup[AbstractFile]): Seq[ClassFileLookup[AbstractFile]] = lookup match {
- case cp: ClassPath[_] => cp.entries
- case cp: AggregateFlatClassPath => cp.aggregates
- case cp: FlatClassPath => Seq(cp)
+ def entries(lookup: ClassPath): Seq[ClassPath] = lookup match {
+ case cp: AggregateClassPath => cp.aggregates
+ case cp: ClassPath => Seq(cp)
}
val dir = AbstractFile.getDirectory(path) // if path is a `jar`, this is a FileZipArchive (isDirectory is true)
val canonical = dir.canonicalPath // this is the canonical path of the .jar
- def matchesCanonical(e: ClassFileLookup[AbstractFile]) = origin(e) match {
+ def matchesCanonical(e: ClassPath) = origin(e) match {
case Some(opath) =>
AbstractFile.getDirectory(opath).canonicalPath == canonical
case None =>
@@ -839,7 +820,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
}
entries(classPath) find matchesCanonical match {
case Some(oldEntry) =>
- Some(oldEntry -> ClassFileLookup.createForFile(dir, classPath, settings))
+ Some(oldEntry -> ClassPathFactory.newClassPath(dir, settings))
case None =>
error(s"Error adding entry to classpath. During invalidation, no entry named $path in classpath $classPath")
None
@@ -849,19 +830,15 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
if (subst.nonEmpty) {
platform updateClassPath subst
informProgress(s"classpath updated on entries [${subst.keys mkString ","}]")
- def mkClassPath(elems: Iterable[ClassFileLookup[AbstractFile]]): ClassFileLookup[AbstractFile] =
+ def mkClassPath(elems: Iterable[ClassPath]): ClassPath =
if (elems.size == 1) elems.head
- else ClassFileLookup.createAggregate(elems, classPath)
+ else AggregateClassPath.createAggregate(elems.toSeq: _*)
val oldEntries = mkClassPath(subst.keys)
val newEntries = mkClassPath(subst.values)
classPath match {
- case rcp: ClassPath[_] => mergeNewEntriesRecursive(
- newEntries.asInstanceOf[ClassPath[AbstractFile]], RootClass, Some(rcp), Some(oldEntries.asInstanceOf[ClassPath[AbstractFile]]),
- invalidated, failed)
-
- case fcp: FlatClassPath => mergeNewEntriesFlat(
+ case cp: ClassPath => mergeNewEntries(
RootClass, "",
- oldEntries.asInstanceOf[FlatClassPath], newEntries.asInstanceOf[FlatClassPath], fcp,
+ oldEntries, newEntries, cp,
invalidated, failed)
}
}
@@ -872,69 +849,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
show("could not invalidate system packages", failed)
}
- /** Merges new classpath entries into the symbol table
- *
- * @param newEntries The new classpath entries
- * @param root The root symbol to be resynced (a package class)
- * @param allEntries Optionally, the corresponding package in the complete current classpath
- * @param oldEntries Optionally, the corresponding package in the old classpath entries
- * @param invalidated A listbuffer collecting the invalidated package classes
- * @param failed A listbuffer collecting system package classes which could not be invalidated
- *
- * The merging strategy is determined by the absence or presence of classes and packages.
- *
- * If either oldEntries or newEntries contains classes, root is invalidated provided that a corresponding package
- * exists in allEntries. Otherwise it is removed.
- * Otherwise, the action is determined by the following matrix, with columns:
- *
- * old sym action
- * + + recurse into all child packages of newEntries
- * - + invalidate root
- * - - create and enter root
- *
- * Here, old means classpath, and sym means symboltable. + is presence of an entry in its column, - is absence.
- */
- private def mergeNewEntriesRecursive(newEntries: ClassPath[AbstractFile], root: ClassSymbol,
- allEntries: Option[ClassPath[AbstractFile]], oldEntries: Option[ClassPath[AbstractFile]],
- invalidated: mutable.ListBuffer[ClassSymbol], failed: mutable.ListBuffer[ClassSymbol]) {
- ifDebug(informProgress(s"syncing $root, $oldEntries -> $newEntries"))
-
- val getPackageName: ClassPath[AbstractFile] => String = _.name
- def hasClasses(cp: Option[ClassPath[AbstractFile]]) = cp.isDefined && cp.get.classes.nonEmpty
- def invalidateOrRemove(root: ClassSymbol) = {
- allEntries match {
- case Some(cp) => root setInfo new loaders.PackageLoader(cp)
- case None => root.owner.info.decls unlink root.sourceModule
- }
- invalidated += root
- }
- def subPackage(cp: ClassPath[AbstractFile], name: String): Option[ClassPath[AbstractFile]] =
- cp.packages find (cp1 => getPackageName(cp1) == name)
-
- val classesFound = hasClasses(oldEntries) || newEntries.classes.nonEmpty
- if (classesFound && !isSystemPackageClass(root)) {
- invalidateOrRemove(root)
- } else {
- if (classesFound) {
- if (root.isRoot) invalidateOrRemove(EmptyPackageClass)
- else failed += root
- }
- if (oldEntries.isEmpty) invalidateOrRemove(root)
- else
- for (pstr <- newEntries.packages.map(getPackageName)) {
- val pname = newTermName(pstr)
- val pkg = (root.info decl pname) orElse {
- // package does not exist in symbol table, create symbol to track it
- assert(subPackage(oldEntries.get, pstr).isEmpty)
- loaders.enterPackage(root, pstr, new loaders.PackageLoader(allEntries.get))
- }
- mergeNewEntriesRecursive(subPackage(newEntries, pstr).get, pkg.moduleClass.asClass,
- subPackage(allEntries.get, pstr), subPackage(oldEntries.get, pstr),
- invalidated, failed)
- }
- }
- }
-
/**
* Merges new classpath entries into the symbol table
*
@@ -953,20 +867,19 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
* Otherwise, sub-packages in newEntries are looked up in the symbol table (created if
* non-existent) and the merge function is called recursively.
*/
- private def mergeNewEntriesFlat(
- packageClass: ClassSymbol, fullPackageName: String,
- oldEntries: FlatClassPath, newEntries: FlatClassPath, fullClasspath: FlatClassPath,
- invalidated: mutable.ListBuffer[ClassSymbol], failed: mutable.ListBuffer[ClassSymbol]): Unit = {
+ private def mergeNewEntries(packageClass: ClassSymbol, fullPackageName: String,
+ oldEntries: ClassPath, newEntries: ClassPath, fullClasspath: ClassPath,
+ invalidated: mutable.ListBuffer[ClassSymbol], failed: mutable.ListBuffer[ClassSymbol]): Unit = {
ifDebug(informProgress(s"syncing $packageClass, $oldEntries -> $newEntries"))
- def packageExists(cp: FlatClassPath): Boolean = {
+ def packageExists(cp: ClassPath): Boolean = {
val (parent, _) = PackageNameUtils.separatePkgAndClassNames(fullPackageName)
cp.packages(parent).exists(_.name == fullPackageName)
}
def invalidateOrRemove(pkg: ClassSymbol) = {
if (packageExists(fullClasspath))
- pkg setInfo new loaders.PackageLoaderUsingFlatClassPath(fullPackageName, fullClasspath)
+ pkg setInfo new loaders.PackageLoader(fullPackageName, fullClasspath)
else
pkg.owner.info.decls unlink pkg.sourceModule
invalidated += pkg
@@ -984,9 +897,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
val (_, subPackageName) = PackageNameUtils.separatePkgAndClassNames(p.name)
val subPackage = packageClass.info.decl(newTermName(subPackageName)) orElse {
// package does not exist in symbol table, create a new symbol
- loaders.enterPackage(packageClass, subPackageName, new loaders.PackageLoaderUsingFlatClassPath(p.name, fullClasspath))
+ loaders.enterPackage(packageClass, subPackageName, new loaders.PackageLoader(p.name, fullClasspath))
}
- mergeNewEntriesFlat(
+ mergeNewEntries(
subPackage.moduleClass.asClass, p.name,
oldEntries, newEntries, fullClasspath,
invalidated, failed)
diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala
index bf93ad30bc..1f66657d8d 100644
--- a/src/compiler/scala/tools/nsc/ScriptRunner.scala
+++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala
@@ -8,10 +8,8 @@ package tools.nsc
import io.{ AbstractFile, Directory, File, Path }
import java.io.IOException
-import scala.tools.nsc.classpath.DirectoryFlatClassPath
+import scala.tools.nsc.classpath.DirectoryClassPath
import scala.tools.nsc.reporters.{Reporter,ConsoleReporter}
-import scala.tools.nsc.settings.ClassPathRepresentationType
-import scala.tools.nsc.util.ClassPath.DefaultJavaContext
import util.Exceptional.unwrap
/** An object that runs Scala code in script files.
@@ -115,10 +113,7 @@ class ScriptRunner extends HasCompileSocket {
}
def hasClassToRun(d: Directory): Boolean = {
- val cp = settings.YclasspathImpl.value match {
- case ClassPathRepresentationType.Recursive => DefaultJavaContext.newClassPath(AbstractFile.getDirectory(d))
- case ClassPathRepresentationType.Flat => DirectoryFlatClassPath(d.jfile)
- }
+ val cp = DirectoryClassPath(d.jfile)
cp.findClass(mainClass).isDefined
}
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/JavaPlatform.scala b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
index 0e2f059a36..dc63b335cc 100644
--- a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
+++ b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
@@ -7,11 +7,9 @@ package scala.tools.nsc
package backend
import io.AbstractFile
-import scala.tools.nsc.classpath.{AggregateFlatClassPath, FlatClassPath}
-import scala.tools.nsc.settings.ClassPathRepresentationType
-import scala.tools.nsc.util.{ClassFileLookup, ClassPath, MergedClassPath}
-import scala.tools.util.FlatClassPathResolver
+import scala.tools.nsc.classpath.AggregateClassPath
import scala.tools.util.PathResolver
+import scala.tools.nsc.util.ClassPath
trait JavaPlatform extends Platform {
val global: Global
@@ -19,38 +17,20 @@ trait JavaPlatform extends Platform {
import global._
import definitions._
- private[nsc] var currentClassPath: Option[MergedClassPath[AbstractFile]] = None
-
- def classPath: ClassPath[AbstractFile] = {
- assert(settings.YclasspathImpl.value == ClassPathRepresentationType.Recursive,
- "To use recursive classpath representation you must enable it with -YclasspathImpl:recursive compiler option.")
+ private[nsc] var currentClassPath: Option[ClassPath] = None
+ private[nsc] def classPath: ClassPath = {
if (currentClassPath.isEmpty) currentClassPath = Some(new PathResolver(settings).result)
currentClassPath.get
}
- private[nsc] var currentFlatClassPath: Option[FlatClassPath] = None
-
- private[nsc] def flatClassPath: FlatClassPath = {
- assert(settings.YclasspathImpl.value == ClassPathRepresentationType.Flat,
- "To use flat classpath representation you must enable it with -YclasspathImpl:flat compiler option.")
-
- if (currentFlatClassPath.isEmpty) currentFlatClassPath = Some(new FlatClassPathResolver(settings).result)
- currentFlatClassPath.get
- }
-
/** Update classpath with a substituted subentry */
- def updateClassPath(subst: Map[ClassFileLookup[AbstractFile], ClassFileLookup[AbstractFile]]) = global.classPath match {
- case cp: ClassPath[AbstractFile] =>
- val s = subst.asInstanceOf[Map[ClassPath[AbstractFile], ClassPath[AbstractFile]]]
- currentClassPath = Some(new MergedClassPath(cp.entries map (e => s.getOrElse(e, e)), cp.context))
-
- case AggregateFlatClassPath(entries) =>
- val s = subst.asInstanceOf[Map[FlatClassPath, FlatClassPath]]
- currentFlatClassPath = Some(AggregateFlatClassPath(entries map (e => s.getOrElse(e, e))))
+ def updateClassPath(subst: Map[ClassPath, ClassPath]): Unit = global.classPath match {
+ case AggregateClassPath(entries) =>
+ currentClassPath = Some(AggregateClassPath(entries map (e => subst.getOrElse(e, e))))
- case cp: FlatClassPath =>
- currentFlatClassPath = Some(subst.getOrElse(cp, cp).asInstanceOf[FlatClassPath])
+ case cp: ClassPath =>
+ currentClassPath = Some(subst.getOrElse(cp, cp))
}
def platformPhases = List(
diff --git a/src/compiler/scala/tools/nsc/backend/Platform.scala b/src/compiler/scala/tools/nsc/backend/Platform.scala
index 369bcc44ed..e464768bb3 100644
--- a/src/compiler/scala/tools/nsc/backend/Platform.scala
+++ b/src/compiler/scala/tools/nsc/backend/Platform.scala
@@ -6,9 +6,8 @@
package scala.tools.nsc
package backend
-import util.{ClassFileLookup, ClassPath}
import io.AbstractFile
-import scala.tools.nsc.classpath.FlatClassPath
+import scala.tools.nsc.util.ClassPath
/** The platform dependent pieces of Global.
*/
@@ -16,14 +15,11 @@ trait Platform {
val symbolTable: symtab.SymbolTable
import symbolTable._
- /** The old, recursive implementation of compiler classpath. */
- def classPath: ClassPath[AbstractFile]
-
/** The new implementation of compiler classpath. */
- private[nsc] def flatClassPath: FlatClassPath
+ private[nsc] def classPath: ClassPath
/** Update classpath with a substitution that maps entries to entries */
- def updateClassPath(subst: Map[ClassFileLookup[AbstractFile], ClassFileLookup[AbstractFile]])
+ def updateClassPath(subst: Map[ClassPath, ClassPath])
/** Any platform-specific phases. */
def platformPhases: List[SubComponent]
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala
index 32f8c7826f..630b2b6c7f 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala
@@ -9,8 +9,7 @@ import scala.tools.asm.tree.{InsnList, AbstractInsnNode, ClassNode, MethodNode}
import java.io.{StringWriter, PrintWriter}
import scala.tools.asm.util.{CheckClassAdapter, TraceClassVisitor, TraceMethodVisitor, Textifier}
import scala.tools.asm.{ClassReader, ClassWriter, Attribute}
-import scala.collection.convert.decorateAsScala._
-import scala.collection.convert.decorateAsJava._
+import scala.collection.JavaConverters._
import scala.tools.nsc.backend.jvm.analysis.InitialProducer
import scala.tools.nsc.backend.jvm.opt.InlineInfoAttributePrototype
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
index 6d3d458324..5d152ef0e8 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
@@ -34,14 +34,6 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
* Functionality to build the body of ASM MethodNode, except for `synchronized` and `try` expressions.
*/
abstract class PlainBodyBuilder(cunit: CompilationUnit) extends PlainSkelBuilder(cunit) {
- /* If the selector type has a member with the right name,
- * it is the host class; otherwise the symbol's owner.
- */
- def findHostClass(selector: Type, sym: Symbol) = selector member sym.name match {
- case NoSymbol => debuglog(s"Rejecting $selector as host class for $sym") ; sym.owner
- case _ => selector.typeSymbol
- }
-
/* ---------------- helper utils for generating methods and code ---------------- */
def emit(opc: Int) { mnode.visitInsn(opc) }
@@ -69,12 +61,14 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
def genStat(tree: Tree) {
lineNumber(tree)
tree match {
- case Assign(lhs @ Select(_, _), rhs) =>
+ case Assign(lhs @ Select(qual, _), rhs) =>
val isStatic = lhs.symbol.isStaticMember
if (!isStatic) { genLoadQualifier(lhs) }
genLoad(rhs, symInfoTK(lhs.symbol))
lineNumber(tree)
- fieldStore(lhs.symbol)
+ // receiverClass is used in the bytecode to access the field. using sym.owner may lead to IllegalAccessError, SI-4283
+ val receiverClass = qual.tpe.typeSymbol
+ fieldStore(lhs.symbol, receiverClass)
case Assign(lhs, rhs) =>
val s = lhs.symbol
@@ -123,15 +117,16 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
// binary operation
case rarg :: Nil =>
- resKind = tpeTK(larg).maxType(tpeTK(rarg))
- if (scalaPrimitives.isShiftOp(code) || scalaPrimitives.isBitwiseOp(code)) {
+ val isShiftOp = scalaPrimitives.isShiftOp(code)
+ resKind = tpeTK(larg).maxType(if (isShiftOp) INT else tpeTK(rarg))
+
+ if (isShiftOp || scalaPrimitives.isBitwiseOp(code)) {
assert(resKind.isIntegralType || (resKind == BOOL),
s"$resKind incompatible with arithmetic modulo operation.")
}
genLoad(larg, resKind)
- genLoad(rarg, // check .NET size of shift arguments!
- if (scalaPrimitives.isShiftOp(code)) INT else resKind)
+ genLoad(rarg, if (isShiftOp) INT else resKind)
(code: @switch) match {
case ADD => bc add resKind
@@ -169,21 +164,13 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
genLoad(args.head, INT)
generatedType = k.asArrayBType.componentType
bc.aload(elementType)
- }
- else if (scalaPrimitives.isArraySet(code)) {
- args match {
- case a1 :: a2 :: Nil =>
- genLoad(a1, INT)
- genLoad(a2)
- // the following line should really be here, but because of bugs in erasure
- // we pretend we generate whatever type is expected from us.
- //generatedType = UNIT
- bc.astore(elementType)
- case _ =>
- abort(s"Too many arguments for array set operation: $tree")
- }
- }
- else {
+ } else if (scalaPrimitives.isArraySet(code)) {
+ val List(a1, a2) = args
+ genLoad(a1, INT)
+ genLoad(a2)
+ generatedType = UNIT
+ bc.astore(elementType)
+ } else {
generatedType = INT
emit(asm.Opcodes.ARRAYLENGTH)
}
@@ -338,26 +325,22 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
assert(tree.symbol.isModule, s"Selection of non-module from empty package: $tree sym: ${tree.symbol} at: ${tree.pos}")
genLoadModule(tree)
- case Select(qualifier, selector) =>
+ case Select(qualifier, _) =>
val sym = tree.symbol
generatedType = symInfoTK(sym)
- val hostClass = findHostClass(qualifier.tpe, sym)
- debuglog(s"Host class of $sym with qual $qualifier (${qualifier.tpe}) is $hostClass")
val qualSafeToElide = treeInfo isQualifierSafeToElide qualifier
-
def genLoadQualUnlessElidable() { if (!qualSafeToElide) { genLoadQualifier(tree) } }
-
+ // receiverClass is used in the bytecode to access the field. using sym.owner may lead to IllegalAccessError, SI-4283
+ def receiverClass = qualifier.tpe.typeSymbol
if (sym.isModule) {
genLoadQualUnlessElidable()
genLoadModule(tree)
- }
- else if (sym.isStaticMember) {
+ } else if (sym.isStaticMember) {
genLoadQualUnlessElidable()
- fieldLoad(sym, hostClass)
- }
- else {
+ fieldLoad(sym, receiverClass)
+ } else {
genLoadQualifier(tree)
- fieldLoad(sym, hostClass)
+ fieldLoad(sym, receiverClass)
}
case Ident(name) =>
@@ -410,24 +393,18 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
/*
* must-single-thread
*/
- def fieldLoad( field: Symbol, hostClass: Symbol = null) {
- fieldOp(field, isLoad = true, hostClass)
- }
+ def fieldLoad(field: Symbol, hostClass: Symbol): Unit = fieldOp(field, isLoad = true, hostClass)
+
/*
* must-single-thread
*/
- def fieldStore(field: Symbol, hostClass: Symbol = null) {
- fieldOp(field, isLoad = false, hostClass)
- }
+ def fieldStore(field: Symbol, hostClass: Symbol): Unit = fieldOp(field, isLoad = false, hostClass)
/*
* must-single-thread
*/
- private def fieldOp(field: Symbol, isLoad: Boolean, hostClass: Symbol) {
- // LOAD_FIELD.hostClass , CALL_METHOD.hostClass , and #4283
- val owner =
- if (hostClass == null) internalName(field.owner)
- else internalName(hostClass)
+ private def fieldOp(field: Symbol, isLoad: Boolean, hostClass: Symbol): Unit = {
+ val owner = internalName(if (hostClass == null) field.owner else hostClass)
val fieldJName = field.javaSimpleName.toString
val fieldDescr = symInfoTK(field).descriptor
val isStatic = field.isStaticMember
@@ -435,7 +412,6 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
if (isLoad) { if (isStatic) asm.Opcodes.GETSTATIC else asm.Opcodes.GETFIELD }
else { if (isStatic) asm.Opcodes.PUTSTATIC else asm.Opcodes.PUTFIELD }
mnode.visitFieldInsn(opc, owner, fieldJName, fieldDescr)
-
}
// ---------------- emitting constant values ----------------
@@ -532,21 +508,6 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
var generatedType = expectedType
lineNumber(app)
- def genSuperApply(hostClass: Symbol, fun: Symbol, args: List[Tree]) = {
- // 'super' call: Note: since constructors are supposed to
- // return an instance of what they construct, we have to take
- // special care. On JVM they are 'void', and Scala forbids (syntactically)
- // to call super constructors explicitly and/or use their 'returned' value.
- // therefore, we can ignore this fact, and generate code that leaves nothing
- // on the stack (contrary to what the type in the AST says).
-
- val invokeStyle = InvokeStyle.Super
- mnode.visitVarInsn(asm.Opcodes.ALOAD, 0)
- genLoadArguments(args, paramTKs(app))
- genCallMethod(fun, invokeStyle, app.pos, hostClass)
- generatedType = methodBTypeFromSymbol(fun).returnType
- }
-
app match {
case Apply(TypeApply(fun, targs), _) =>
@@ -594,19 +555,33 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
generatedType = genTypeApply()
- case Apply(fun @ Select(Super(qual, mix), _), args) =>
- val hostClass = qual.symbol.parentSymbols.filter(_.name == mix) match {
- case Nil =>
- // We get here for trees created by SuperSelect which use tpnme.EMPTY as the super qualifier
- // Subsequent code uses the owner of fun.symbol to target the call.
- null
- case parent :: Nil=>
- parent
- case parents =>
- devWarning("ambiguous parent class qualifier: " + qual.symbol.parentSymbols)
- null
+ case Apply(fun @ Select(Super(_, _), _), args) =>
+ def initModule() {
+ // we initialize the MODULE$ field immediately after the super ctor
+ if (!isModuleInitialized &&
+ jMethodName == INSTANCE_CONSTRUCTOR_NAME &&
+ fun.symbol.javaSimpleName.toString == INSTANCE_CONSTRUCTOR_NAME &&
+ isStaticModuleClass(claszSymbol)) {
+ isModuleInitialized = true
+ mnode.visitVarInsn(asm.Opcodes.ALOAD, 0)
+ mnode.visitFieldInsn(
+ asm.Opcodes.PUTSTATIC,
+ thisBType.internalName,
+ strMODULE_INSTANCE_FIELD,
+ thisBType.descriptor
+ )
+ }
}
- genSuperApply(hostClass, fun.symbol, args)
+ // 'super' call: Note: since constructors are supposed to
+ // return an instance of what they construct, we have to take
+ // special care. On JVM they are 'void', and Scala forbids (syntactically)
+ // to call super constructors explicitly and/or use their 'returned' value.
+ // therefore, we can ignore this fact, and generate code that leaves nothing
+ // on the stack (contrary to what the type in the AST says).
+ mnode.visitVarInsn(asm.Opcodes.ALOAD, 0)
+ genLoadArguments(args, paramTKs(app))
+ generatedType = genCallMethod(fun.symbol, InvokeStyle.Super, app.pos)
+ initModule()
// 'new' constructor call: Note: since constructors are
// thought to return an instance of what they construct,
@@ -658,16 +633,16 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
genInvokeDynamicLambda(attachment.target, attachment.arity, attachment.functionalInterface, attachment.sam)
generatedType = methodBTypeFromSymbol(fun.symbol).returnType
- case Apply(fun @ _, List(expr)) if currentRun.runDefinitions.isBox(fun.symbol) =>
+ case Apply(fun, List(expr)) if currentRun.runDefinitions.isBox(fun.symbol) =>
val nativeKind = tpeTK(expr)
genLoad(expr, nativeKind)
val MethodNameAndType(mname, methodType) = srBoxesRuntimeBoxToMethods(nativeKind)
bc.invokestatic(srBoxesRunTimeRef.internalName, mname, methodType.descriptor, app.pos)
- generatedType = boxResultType(fun.symbol) // was typeToBType(fun.symbol.tpe.resultType)
+ generatedType = boxResultType(fun.symbol)
- case Apply(fun @ _, List(expr)) if currentRun.runDefinitions.isUnbox(fun.symbol) =>
+ case Apply(fun, List(expr)) if currentRun.runDefinitions.isUnbox(fun.symbol) =>
genLoad(expr)
- val boxType = unboxResultType(fun.symbol) // was typeToBType(fun.symbol.owner.linkedClassOfClass.tpe)
+ val boxType = unboxResultType(fun.symbol)
generatedType = boxType
val MethodNameAndType(mname, methodType) = srBoxesRuntimeUnboxToMethods(boxType)
bc.invokestatic(srBoxesRunTimeRef.internalName, mname, methodType.descriptor, app.pos)
@@ -675,80 +650,73 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
case app @ Apply(fun, args) =>
val sym = fun.symbol
- if (sym.isLabel) { // jump to a label
+ if (sym.isLabel) { // jump to a label
genLoadLabelArguments(args, labelDef(sym), app.pos)
bc goTo programPoint(sym)
} else if (isPrimitive(sym)) { // primitive method call
generatedType = genPrimitiveOp(app, expectedType)
- } else { // normal method call
-
- def genNormalMethodCall() {
-
- val invokeStyle =
- if (sym.isStaticMember) InvokeStyle.Static
- else if (sym.isPrivate || sym.isClassConstructor) InvokeStyle.Special
- else InvokeStyle.Virtual
-
- if (invokeStyle.hasInstance) {
- genLoadQualifier(fun)
+ } else { // normal method call
+ val invokeStyle =
+ if (sym.isStaticMember) InvokeStyle.Static
+ else if (sym.isPrivate || sym.isClassConstructor) InvokeStyle.Special
+ else InvokeStyle.Virtual
+
+ if (invokeStyle.hasInstance) genLoadQualifier(fun)
+ genLoadArguments(args, paramTKs(app))
+
+ val Select(qual, _) = fun // fun is a Select, also checked in genLoadQualifier
+ if (sym == definitions.Array_clone) {
+ // Special-case Array.clone, introduced in 36ef60e. The goal is to generate this call
+ // as "[I.clone" instead of "java/lang/Object.clone". This is consistent with javac.
+ // Arrays have a public method `clone` (jls 10.7).
+ //
+ // The JVMS is not explicit about this, but that receiver type can be an array type
+ // descriptor (instead of a class internal name):
+ // invokevirtual #2; //Method "[I".clone:()Ljava/lang/Object
+ //
+ // Note that using `Object.clone()` would work as well, but only because the JVM
+ // relaxes protected access specifically if the receiver is an array:
+ // http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/87ee5ee27509/src/share/vm/interpreter/linkResolver.cpp#l439
+ // Example: `class C { override def clone(): Object = "hi" }`
+ // Emitting `def f(c: C) = c.clone()` as `Object.clone()` gives a VerifyError.
+ val target: String = tpeTK(qual).asRefBType.classOrArrayType
+ val methodBType = methodBTypeFromSymbol(sym)
+ bc.invokevirtual(target, sym.javaSimpleName.toString, methodBType.descriptor, app.pos)
+ generatedType = methodBType.returnType
+ } else {
+ val receiverClass = if (!invokeStyle.isVirtual) null else {
+ // receiverClass is used in the bytecode to as the method receiver. using sym.owner
+ // may lead to IllegalAccessErrors, see 9954eaf / aladdin bug 455.
+ val qualSym = qual.tpe.typeSymbol
+ if (qualSym == ArrayClass) {
+ // For invocations like `Array(1).hashCode` or `.wait()`, use Object as receiver
+ // in the bytecode. Using the array descriptor (like we do for clone above) seems
+ // to work as well, but it seems safer not to change this. Javac also uses Object.
+ // Note that array apply/update/length are handled by isPrimitive (above).
+ assert(sym.owner == ObjectClass, s"unexpected array call: ${show(app)}")
+ ObjectClass
+ } else qualSym
}
- genLoadArguments(args, paramTKs(app))
-
- // In "a couple cases", squirrel away a extra information (hostClass, targetTypeKind). TODO Document what "in a couple cases" refers to.
- var hostClass: Symbol = null
- var targetTypeKind: BType = null
- fun match {
- case Select(qual, _) =>
- val qualSym = findHostClass(qual.tpe, sym)
- if (qualSym == ArrayClass) {
- targetTypeKind = tpeTK(qual)
- log(s"Stored target type kind for ${sym.fullName} as $targetTypeKind")
- }
- else {
- hostClass = qualSym
- if (qual.tpe.typeSymbol != qualSym) {
- log(s"Precisified host class for $sym from ${qual.tpe.typeSymbol.fullName} to ${qualSym.fullName}")
- }
- }
-
- case _ =>
- }
- if ((targetTypeKind != null) && (sym == definitions.Array_clone) && invokeStyle.isVirtual) {
- // An invokevirtual points to a CONSTANT_Methodref_info which in turn points to a
- // CONSTANT_Class_info of the receiver type.
- // The JVMS is not explicit about this, but that receiver type may be an array type
- // descriptor (instead of a class internal name):
- // invokevirtual #2; //Method "[I".clone:()Ljava/lang/Object
- val target: String = targetTypeKind.asRefBType.classOrArrayType
- bc.invokevirtual(target, "clone", "()Ljava/lang/Object;", app.pos)
- }
- else {
- genCallMethod(sym, invokeStyle, app.pos, hostClass)
- // Check if the Apply tree has an InlineAnnotatedAttachment, added by the typer
- // for callsites marked `f(): @inline/noinline`. For nullary calls, the attachment
- // is on the Select node (not on the Apply node added by UnCurry).
- def checkInlineAnnotated(t: Tree): Unit = {
- if (t.hasAttachment[InlineAnnotatedAttachment]) lastInsn match {
- case m: MethodInsnNode =>
- if (app.hasAttachment[NoInlineCallsiteAttachment.type]) noInlineAnnotatedCallsites += m
- else inlineAnnotatedCallsites += m
- case _ =>
- } else t match {
- case Apply(fun, _) => checkInlineAnnotated(fun)
- case _ =>
- }
+ generatedType = genCallMethod(sym, invokeStyle, app.pos, receiverClass)
+
+ // Check if the Apply tree has an InlineAnnotatedAttachment, added by the typer
+ // for callsites marked `f(): @inline/noinline`. For nullary calls, the attachment
+ // is on the Select node (not on the Apply node added by UnCurry).
+ def recordInlineAnnotated(t: Tree): Unit = {
+ if (t.hasAttachment[InlineAnnotatedAttachment]) lastInsn match {
+ case m: MethodInsnNode =>
+ if (app.hasAttachment[NoInlineCallsiteAttachment.type]) noInlineAnnotatedCallsites += m
+ else inlineAnnotatedCallsites += m
+ case _ =>
+ } else t match {
+ case Apply(fun, _) => recordInlineAnnotated(fun)
+ case _ =>
}
- checkInlineAnnotated(app)
}
-
- } // end of genNormalMethodCall()
-
- genNormalMethodCall()
-
- generatedType = methodBTypeFromSymbol(sym).returnType
+ recordInlineAnnotated(app)
+ }
}
-
}
generatedType
@@ -1026,11 +994,11 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
def genStringConcat(tree: Tree): BType = {
lineNumber(tree)
liftStringConcat(tree) match {
-
// Optimization for expressions of the form "" + x. We can avoid the StringBuilder.
case List(Literal(Constant("")), arg) =>
genLoad(arg, ObjectRef)
genCallMethod(String_valueOf, InvokeStyle.Static, arg.pos)
+
case concatenations =>
bc.genStartConcat(tree.pos)
for (elem <- concatenations) {
@@ -1047,82 +1015,83 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
bc.genConcat(elemType, loadedElem.pos)
}
bc.genEndConcat(tree.pos)
-
}
-
StringRef
}
- def genCallMethod(method: Symbol, style: InvokeStyle, pos: Position, hostClass0: Symbol = null) {
-
- val siteSymbol = claszSymbol
- val hostSymbol = if (hostClass0 == null) method.owner else hostClass0
+ /**
+ * Generate a method invocation. If `specificReceiver != null`, it is used as receiver in the
+ * invocation instruction, otherwise `method.owner`. A specific receiver class is needed to
+ * prevent an IllegalAccessError, (aladdin bug 455).
+ */
+ def genCallMethod(method: Symbol, style: InvokeStyle, pos: Position, specificReceiver: Symbol = null): BType = {
val methodOwner = method.owner
- // info calls so that types are up to date; erasure may add lateINTERFACE to traits
- hostSymbol.info ; methodOwner.info
-
- def needsInterfaceCall(sym: Symbol) = (
- sym.isTraitOrInterface
- || sym.isJavaDefined && sym.isNonBottomSubClass(definitions.ClassfileAnnotationClass)
- )
+ // the class used in the invocation's method descriptor in the classfile
+ val receiverClass = {
+ if (specificReceiver != null)
+ assert(style.isVirtual || specificReceiver == methodOwner, s"specificReceiver can only be specified for virtual calls. $method - $specificReceiver")
+
+ val useSpecificReceiver = specificReceiver != null && !specificReceiver.isBottomClass
+ val receiver = if (useSpecificReceiver) specificReceiver else methodOwner
+
+ // workaround for a JVM bug: https://bugs.openjdk.java.net/browse/JDK-8154587
+ // when an interface method overrides a member of Object (note that all interfaces implicitly
+ // have superclass Object), the receiver needs to be the interface declaring the override (and
+ // not a sub-interface that inherits it). example:
+ // trait T { override def clone(): Object = "" }
+ // trait U extends T
+ // class C extends U
+ // class D { def f(u: U) = u.clone() }
+ // The invocation `u.clone()` needs `T` as a receiver:
+ // - using Object is illegal, as Object.clone is protected
+ // - using U results in a `NoSuchMethodError: U.clone. This is the JVM bug.
+ // Note that a mixin forwarder is generated, so the correct method is executed in the end:
+ // class C { override def clone(): Object = super[T].clone() }
+ val isTraitMethodOverridingObjectMember = {
+ receiver != methodOwner && // fast path - the boolean is used to pick either of these two, if they are the same it does not matter
+ style.isVirtual &&
+ receiver.isTraitOrInterface &&
+ ObjectTpe.decl(method.name).exists && // fast path - compute overrideChain on the next line only if necessary
+ method.overrideChain.last.owner == ObjectClass
+ }
+ if (isTraitMethodOverridingObjectMember) methodOwner else receiver
+ }
- val isTraitCallToObjectMethod =
- hostSymbol != methodOwner && methodOwner.isTraitOrInterface && ObjectTpe.decl(method.name) != NoSymbol && method.overrideChain.last.owner == ObjectClass
+ receiverClass.info // ensure types the type is up to date; erasure may add lateINTERFACE to traits
+ val receiverName = internalName(receiverClass)
- // whether to reference the type of the receiver or
- // the type of the method owner
- val useMethodOwner = ((
- !style.isVirtual
- || hostSymbol.isBottomClass
- || methodOwner == definitions.ObjectClass
- ) && !(style.isSuper && hostSymbol != null)) || isTraitCallToObjectMethod
- val receiver = if (useMethodOwner) methodOwner else hostSymbol
- val jowner = internalName(receiver)
+ // super calls are only allowed to direct parents
+ if (style.isSuper && receiverClass.isTraitOrInterface && !cnode.interfaces.contains(receiverName)) {
+ thisBType.info.get.inlineInfo.lateInterfaces += receiverName
+ cnode.interfaces.add(receiverName)
+ }
- if (style.isSuper && (isTraitCallToObjectMethod || receiver.isTraitOrInterface) && !cnode.interfaces.contains(jowner))
- cnode.interfaces.add(jowner)
+ def needsInterfaceCall(sym: Symbol) = {
+ sym.isTraitOrInterface ||
+ sym.isJavaDefined && sym.isNonBottomSubClass(definitions.ClassfileAnnotationClass)
+ }
val jname = method.javaSimpleName.toString
val bmType = methodBTypeFromSymbol(method)
val mdescr = bmType.descriptor
- def initModule() {
- // we initialize the MODULE$ field immediately after the super ctor
- if (!isModuleInitialized &&
- jMethodName == INSTANCE_CONSTRUCTOR_NAME &&
- jname == INSTANCE_CONSTRUCTOR_NAME &&
- isStaticModuleClass(siteSymbol)) {
- isModuleInitialized = true
- mnode.visitVarInsn(asm.Opcodes.ALOAD, 0)
- mnode.visitFieldInsn(
- asm.Opcodes.PUTSTATIC,
- thisName,
- strMODULE_INSTANCE_FIELD,
- "L" + thisName + ";"
- )
- }
- }
-
- if (style.isStatic) { bc.invokestatic (jowner, jname, mdescr, pos) }
- else if (style.isSpecial) { bc.invokespecial (jowner, jname, mdescr, pos) }
- else if (style.isVirtual) {
- if (needsInterfaceCall(receiver)) { bc.invokeinterface(jowner, jname, mdescr, pos) }
- else { bc.invokevirtual (jowner, jname, mdescr, pos) }
- }
- else {
- assert(style.isSuper, s"An unknown InvokeStyle: $style")
- bc.invokespecial(jowner, jname, mdescr, pos)
- initModule()
+ import InvokeStyle._
+ style match {
+ case Static => bc.invokestatic (receiverName, jname, mdescr, pos)
+ case Special => bc.invokespecial (receiverName, jname, mdescr, pos)
+ case Virtual =>
+ if (needsInterfaceCall(receiverClass)) bc.invokeinterface(receiverName, jname, mdescr, pos)
+ else bc.invokevirtual (receiverName, jname, mdescr, pos)
+ case Super => bc.invokespecial (receiverName, jname, mdescr, pos)
}
+ bmType.returnType
} // end of genCallMethod()
/* Generate the scala ## method. */
def genScalaHash(tree: Tree, applyPos: Position): BType = {
- genLoadModule(ScalaRunTimeModule) // TODO why load ScalaRunTimeModule if ## has InvokeStyle of Static(false) ?
genLoad(tree, ObjectRef)
genCallMethod(hashMethodSym, InvokeStyle.Static, applyPos)
- INT
}
/*
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 4c41cfc380..bddc41e5c6 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
@@ -59,7 +59,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
// current class
var cnode: asm.tree.ClassNode = null
- var thisName: String = null // the internal name of the class being emitted
+ var thisBType: ClassBType = null
var claszSymbol: Symbol = null
var isCZParcelable = false
@@ -91,9 +91,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
isCZParcelable = isAndroidParcelableClass(claszSymbol)
isCZStaticModule = isStaticModuleClass(claszSymbol)
isCZRemote = isRemote(claszSymbol)
- thisName = internalName(claszSymbol)
-
- val classBType = classBTypeFromSymbol(claszSymbol)
+ thisBType = classBTypeFromSymbol(claszSymbol)
cnode = new asm.tree.ClassNode()
@@ -114,7 +112,6 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
gen(cd.impl)
-
val shouldAddLambdaDeserialize = (
settings.target.value == "jvm-1.8"
&& settings.Ydelambdafy.value == "method"
@@ -123,7 +120,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
if (shouldAddLambdaDeserialize)
backendUtils.addLambdaDeserialize(cnode)
- cnode.visitAttribute(classBType.inlineInfoAttribute.get)
+ cnode.visitAttribute(thisBType.inlineInfoAttribute.get)
if (AsmUtils.traceClassEnabled && cnode.name.contains(AsmUtils.traceClassPattern))
AsmUtils.traceClass(cnode)
@@ -144,7 +141,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
val thisSignature = getGenericSignature(claszSymbol, claszSymbol.owner)
cnode.visit(classfileVersion, flags,
- thisName, thisSignature,
+ thisBType.internalName, thisSignature,
superClass, interfaceNames.toArray)
if (emitSource) {
@@ -157,7 +154,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
case _ => ()
}
- val ssa = getAnnotPickle(thisName, claszSymbol)
+ val ssa = getAnnotPickle(thisBType.internalName, claszSymbol)
cnode.visitAttribute(if (ssa.isDefined) pickleMarkerLocal else pickleMarkerForeign)
emitAnnotations(cnode, claszSymbol.annotations ++ ssa)
@@ -167,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) {
@@ -178,7 +174,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
}
if (isCandidateForForwarders) {
log(s"Adding static forwarders from '$claszSymbol' to implementations in '$lmoc'")
- addForwarders(isRemote(claszSymbol), cnode, thisName, lmoc.moduleClass)
+ addForwarders(isRemote(claszSymbol), cnode, thisBType.internalName, lmoc.moduleClass)
}
}
}
@@ -196,7 +192,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
val fv =
cnode.visitField(GenBCode.PublicStaticFinal, // TODO confirm whether we really don't want ACC_SYNTHETIC nor ACC_DEPRECATED
strMODULE_INSTANCE_FIELD,
- "L" + thisName + ";",
+ thisBType.descriptor,
null, // no java-generic-signature
null // no initial value
)
@@ -220,11 +216,11 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
/* "legacy static initialization" */
if (isCZStaticModule) {
- clinit.visitTypeInsn(asm.Opcodes.NEW, thisName)
+ clinit.visitTypeInsn(asm.Opcodes.NEW, thisBType.internalName)
clinit.visitMethodInsn(asm.Opcodes.INVOKESPECIAL,
- thisName, INSTANCE_CONSTRUCTOR_NAME, "()V", false)
+ thisBType.internalName, INSTANCE_CONSTRUCTOR_NAME, "()V", false)
}
- if (isCZParcelable) { legacyAddCreatorCode(clinit, cnode, thisName) }
+ if (isCZParcelable) { legacyAddCreatorCode(clinit, cnode, thisBType.internalName) }
clinit.visitInsn(asm.Opcodes.RETURN)
clinit.visitMaxs(0, 0) // just to follow protocol, dummy arguments
@@ -604,7 +600,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
if (!hasStaticBitSet) {
mnode.visitLocalVariable(
"this",
- "L" + thisName + ";",
+ thisBType.descriptor,
null,
veryFirstProgramPoint,
onePastLastProgramPoint,
@@ -686,8 +682,8 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
val jname = callee.javaSimpleName.toString
val jtype = methodBTypeFromSymbol(callee).descriptor
insnParcA = new asm.tree.MethodInsnNode(asm.Opcodes.INVOKESTATIC, jowner, jname, jtype, false)
- // PUTSTATIC `thisName`.CREATOR;
- insnParcB = new asm.tree.FieldInsnNode(asm.Opcodes.PUTSTATIC, thisName, "CREATOR", andrFieldDescr)
+ // PUTSTATIC `thisBType.internalName`.CREATOR;
+ insnParcB = new asm.tree.FieldInsnNode(asm.Opcodes.PUTSTATIC, thisBType.internalName, "CREATOR", andrFieldDescr)
}
// insert a few instructions for initialization before each return instruction
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
index f6bccca050..2637d21050 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
@@ -7,7 +7,7 @@ package scala.tools.nsc
package backend.jvm
import scala.annotation.switch
-import scala.collection.{mutable, concurrent}
+import scala.collection.{concurrent, mutable}
import scala.collection.concurrent.TrieMap
import scala.reflect.internal.util.Position
import scala.tools.asm
@@ -17,7 +17,8 @@ import scala.tools.nsc.backend.jvm.BTypes.{InlineInfo, MethodInlineInfo}
import scala.tools.nsc.backend.jvm.BackendReporting._
import scala.tools.nsc.backend.jvm.analysis.BackendUtils
import scala.tools.nsc.backend.jvm.opt._
-import scala.collection.convert.decorateAsScala._
+import scala.collection.JavaConverters._
+import scala.collection.mutable.ListBuffer
import scala.tools.nsc.settings.ScalaSettings
/**
@@ -180,8 +181,6 @@ abstract class BTypes {
Some(classBTypeFromParsedClassfile(superName))
}
- val interfaces: List[ClassBType] = classNode.interfaces.asScala.map(classBTypeFromParsedClassfile)(collection.breakOut)
-
val flags = classNode.access
/**
@@ -226,6 +225,9 @@ abstract class BTypes {
val inlineInfo = inlineInfoFromClassfile(classNode)
+ val classfileInterfaces: List[ClassBType] = classNode.interfaces.asScala.map(classBTypeFromParsedClassfile)(collection.breakOut)
+ val interfaces = classfileInterfaces.filterNot(i => inlineInfo.lateInterfaces.contains(i.internalName))
+
classBType.info = Right(ClassInfo(superClass, interfaces, flags, nestedClasses, nestedInfo, inlineInfo))
classBType
}
@@ -1144,7 +1146,27 @@ object BTypes {
final case class InlineInfo(isEffectivelyFinal: Boolean,
sam: Option[String],
methodInfos: Map[String, MethodInlineInfo],
- warning: Option[ClassInlineInfoWarning])
+ warning: Option[ClassInlineInfoWarning]) {
+ /**
+ * A super call (invokespecial) to a default method T.m is only allowed if the interface T is
+ * a direct parent of the class. Super calls are introduced for example in Mixin when generating
+ * forwarder methods:
+ *
+ * trait T { override def clone(): Object = "hi" }
+ * trait U extends T
+ * class C extends U
+ *
+ * The class C gets a forwarder that invokes T.clone(). During code generation the interface T
+ * is added as direct parent to class C. Note that T is not a (direct) parent in the frontend
+ * type of class C.
+ *
+ * All interfaces that are added to a class during code generation are added to this buffer and
+ * stored in the InlineInfo classfile attribute. This ensures that the ClassBTypes for a
+ * specific class is the same no matter if it's constructed from a Symbol or from a classfile.
+ * This is tested in BTypesFromClassfileTest.
+ */
+ val lateInterfaces: ListBuffer[InternalName] = ListBuffer.empty
+ }
val EmptyInlineInfo = InlineInfo(false, None, Map.empty, None)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala b/src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala
index 01206aa6eb..4287c24dc8 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala
@@ -42,15 +42,15 @@ object BackendReporting {
def assertionError(message: String): Nothing = throw new AssertionError(message)
implicit class RightBiasedEither[A, B](val v: Either[A, B]) extends AnyVal {
- def map[U](f: B => U) = v.right.map(f)
- def flatMap[BB](f: B => Either[A, BB]) = v.right.flatMap(f)
+ def map[C](f: B => C): Either[A, C] = v.right.map(f)
+ def flatMap[C](f: B => Either[A, C]): Either[A, C] = v.right.flatMap(f)
def withFilter(f: B => Boolean)(implicit empty: A): Either[A, B] = v match {
case Left(_) => v
case Right(e) => if (f(e)) v else Left(empty) // scalaz.\/ requires an implicit Monoid m to get m.empty
}
- def foreach[U](f: B => U) = v.right.foreach(f)
+ def foreach[U](f: B => U): Unit = v.right.foreach(f)
- def getOrElse[BB >: B](alt: => BB): BB = v.right.getOrElse(alt)
+ def getOrElse[C >: B](alt: => C): C = v.right.getOrElse(alt)
/**
* Get the value, fail with an assertion if this is an error.
@@ -101,11 +101,14 @@ object BackendReporting {
else ""
}
- case MethodNotFound(name, descriptor, ownerInternalName, missingClasses) =>
- val (javaDef, others) = missingClasses.partition(_.definedInJavaSource)
- s"The method $name$descriptor could not be found in the class $ownerInternalName or any of its parents." +
- (if (others.isEmpty) "" else others.map(_.internalName).mkString("\nNote that the following parent classes could not be found on the classpath: ", ", ", "")) +
- (if (javaDef.isEmpty) "" else javaDef.map(_.internalName).mkString("\nNote that the following parent classes are defined in Java sources (mixed compilation), no bytecode is available: ", ",", ""))
+ case MethodNotFound(name, descriptor, ownerInternalName, missingClass) =>
+ val missingClassWarning = missingClass match {
+ case None => ""
+ case Some(c) =>
+ if (c.definedInJavaSource) s"\nNote that the parent class ${c.internalName} is defined in a Java source (mixed compilation), no bytecode is available."
+ else s"\nNote that the parent class ${c.internalName} could not be found on the classpath."
+ }
+ s"The method $name$descriptor could not be found in the class $ownerInternalName or any of its parents." + missingClassWarning
case FieldNotFound(name, descriptor, ownerInternalName, missingClass) =>
s"The field node $name$descriptor could not be found because the classfile $ownerInternalName cannot be found on the classpath." +
@@ -127,7 +130,7 @@ object BackendReporting {
}
case class ClassNotFound(internalName: InternalName, definedInJavaSource: Boolean) extends MissingBytecodeWarning
- case class MethodNotFound(name: String, descriptor: String, ownerInternalNameOrArrayDescriptor: InternalName, missingClasses: List[ClassNotFound]) extends MissingBytecodeWarning {
+ case class MethodNotFound(name: String, descriptor: String, ownerInternalNameOrArrayDescriptor: InternalName, missingClass: Option[ClassNotFound]) extends MissingBytecodeWarning {
def isArrayMethod = ownerInternalNameOrArrayDescriptor.charAt(0) == '['
}
case class FieldNotFound(name: String, descriptor: String, ownerInternalName: InternalName, missingClass: Option[ClassNotFound]) extends MissingBytecodeWarning
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
index 4d03f9851e..1feca56923 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
@@ -107,6 +107,7 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
lazy val juHashMapRef : ClassBType = classBTypeFromSymbol(JavaUtilHashMap) // java/util/HashMap
lazy val sbScalaBeanInfoRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.beans.ScalaBeanInfo])
lazy val jliSerializedLambdaRef : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.invoke.SerializedLambda])
+ lazy val jliMethodHandleRef : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.invoke.MethodHandle])
lazy val jliMethodHandlesRef : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.invoke.MethodHandles])
lazy val jliMethodHandlesLookupRef : ClassBType = classBTypeFromSymbol(exitingPickler(getRequiredClass("java.lang.invoke.MethodHandles.Lookup"))) // didn't find a reliable non-stringly-typed way that works for inner classes in the backend
lazy val jliMethodTypeRef : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.invoke.MethodType])
@@ -251,7 +252,7 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
)
}
- lazy val hashMethodSym: Symbol = getMember(ScalaRunTimeModule, nme.hash_)
+ lazy val hashMethodSym: Symbol = getMember(RuntimeStaticsModule, nme.anyHash)
// TODO @lry avoiding going through through missingHook for every line in the REPL: https://github.com/scala/scala/commit/8d962ed4ddd310cc784121c426a2e3f56a112540
lazy val AndroidParcelableInterface : Symbol = getClassIfDefined("android.os.Parcelable")
@@ -320,6 +321,7 @@ trait CoreBTypesProxyGlobalIndependent[BTS <: BTypes] {
def jliCallSiteRef : ClassBType
def jliMethodTypeRef : ClassBType
def jliSerializedLambdaRef : ClassBType
+ def jliMethodHandleRef : ClassBType
def jliMethodHandlesLookupRef : ClassBType
def srBoxesRunTimeRef : ClassBType
def srBoxedUnitRef : ClassBType
@@ -383,6 +385,7 @@ final class CoreBTypesProxy[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes:
def juHashMapRef : ClassBType = _coreBTypes.juHashMapRef
def sbScalaBeanInfoRef : ClassBType = _coreBTypes.sbScalaBeanInfoRef
def jliSerializedLambdaRef : ClassBType = _coreBTypes.jliSerializedLambdaRef
+ def jliMethodHandleRef : ClassBType = _coreBTypes.jliMethodHandleRef
def jliMethodHandlesRef : ClassBType = _coreBTypes.jliMethodHandlesRef
def jliMethodHandlesLookupRef : ClassBType = _coreBTypes.jliMethodHandlesLookupRef
def jliMethodTypeRef : ClassBType = _coreBTypes.jliMethodTypeRef
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
index b0ec37db97..3520d57599 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
@@ -135,7 +135,7 @@ abstract class GenBCode extends BCodeSyncAndTry {
return
}
else {
- try { withCurrentUnit(item.cunit)(visit(item)) }
+ try { withCurrentUnitNoLog(item.cunit)(visit(item)) }
catch {
case ex: Throwable =>
ex.printStackTrace()
@@ -187,7 +187,7 @@ abstract class GenBCode extends BCodeSyncAndTry {
// -------------- "plain" class --------------
val pcb = new PlainClassBuilder(cunit)
pcb.genPlainClass(cd)
- val outF = if (needsOutFolder) getOutFolder(claszSymbol, pcb.thisName, cunit) else null
+ val outF = if (needsOutFolder) getOutFolder(claszSymbol, pcb.thisBType.internalName, cunit) else null
val plainC = pcb.cnode
// -------------- bean info class, if needed --------------
@@ -221,7 +221,7 @@ abstract class GenBCode extends BCodeSyncAndTry {
*/
class Worker2 {
def runGlobalOptimizations(): Unit = {
- import scala.collection.convert.decorateAsScala._
+ import scala.collection.JavaConverters._
// add classes to the bytecode repo before building the call graph: the latter needs to
// look up classes and methods in the code repo.
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala
index f1facce173..f94642389d 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala
@@ -12,8 +12,7 @@ import scala.tools.nsc.backend.jvm.BTypes._
import scala.tools.nsc.backend.jvm.opt.BytecodeUtils._
import java.lang.invoke.LambdaMetafactory
import scala.collection.mutable
-import scala.collection.convert.decorateAsJava._
-import scala.collection.convert.decorateAsScala._
+import scala.collection.JavaConverters._
/**
* This component hosts tools and utilities used in the backend that require access to a `BTypes`
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerImpl.scala b/src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerImpl.scala
index 6b645cb803..8af4bd4d5d 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerImpl.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerImpl.scala
@@ -18,7 +18,7 @@ import scala.tools.asm.tree.analysis._
import opt.BytecodeUtils._
-import scala.collection.convert.decorateAsScala._
+import scala.collection.JavaConverters._
/**
* This class provides additional queries over ASM's built-in `SourceValue` analysis.
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala
index 16fe2e5cff..a4cd8fce1e 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala
@@ -12,7 +12,7 @@ import scala.tools.asm.Type
import scala.tools.asm.Opcodes._
import scala.tools.asm.tree._
import scala.collection.mutable
-import scala.collection.convert.decorateAsScala._
+import scala.collection.JavaConverters._
import scala.tools.nsc.backend.jvm.BTypes.InternalName
import scala.tools.nsc.backend.jvm.opt.BytecodeUtils._
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala
index 4492d0baf5..16590ec75c 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala
@@ -9,12 +9,11 @@ package opt
import scala.tools.asm
import asm.tree._
-import scala.collection.convert.decorateAsScala._
-import scala.collection.concurrent
+import scala.collection.JavaConverters._
+import scala.collection.{concurrent, mutable}
import scala.tools.asm.Attribute
import scala.tools.nsc.backend.jvm.BackendReporting._
-import scala.tools.nsc.io.AbstractFile
-import scala.tools.nsc.util.ClassFileLookup
+import scala.tools.nsc.util.ClassPath
import BytecodeUtils._
import ByteCodeRepository._
import BTypes.InternalName
@@ -26,7 +25,7 @@ import java.util.concurrent.atomic.AtomicLong
*
* @param classPath The compiler classpath where classfiles are searched and read from.
*/
-class ByteCodeRepository[BT <: BTypes](val classPath: ClassFileLookup[AbstractFile], val btypes: BT) {
+class ByteCodeRepository[BT <: BTypes](val classPath: ClassPath, val btypes: BT) {
import btypes._
/**
@@ -132,38 +131,135 @@ class ByteCodeRepository[BT <: BTypes](val classPath: ClassFileLookup[AbstractFi
* The method node for a method matching `name` and `descriptor`, accessed in class `ownerInternalNameOrArrayDescriptor`.
* The declaration of the method may be in one of the parents.
*
- * TODO: make sure we always return the right method, the one being invoked. write tests.
- * - if there's an abstract and a concrete one. could possibly somehow the abstract be returned?
- * - with traits and default methods, if there is more than one default method inherited and
- * no override: what should be returned? We should not just inline one of the two.
+ * Note that the JVM spec performs method lookup in two steps: resolution and selection.
+ *
+ * Method resolution, defined in jvms-5.4.3.3 and jvms-5.4.3.4, is the first step and is identical
+ * for all invocation styles (virtual, interface, special, static). If C is the receiver class
+ * in the invocation instruction:
+ * 1 find a matching method (name and descriptor) in C
+ * 2 then in C's superclasses
+ * 3 then find the maximally-specific matching superinterface methods, succeed if there's a
+ * single non-abstract one. static and private methods in superinterfaces are not considered.
+ * 4 then pick a random non-static, non-private superinterface method.
+ * 5 then fail.
+ *
+ * Note that for an `invokestatic` instruction, a method reference `B.m` may resolve to `A.m`, if
+ * class `B` doesn't specify a matching method `m`, but the parent `A` does.
+ *
+ * Selection depends on the invocation style and is defined in jvms-6.5.
+ * - invokestatic: invokes the resolved method
+ * - invokevirtual / invokeinterface: searches for an override of the resolved method starting
+ * at the dynamic receiver type. the search procedure is basically the same as in resolution,
+ * but it fails at 4 instead of picking a superinterface method at random.
+ * - invokespecial: if C is the receiver in the invocation instruction, searches for an override
+ * of the resolved method starting at
+ * - the superclass of the current class, if C is a superclass of the current class
+ * - C otherwise
+ * again, the search procedure is the same.
+ *
+ * In the method here we implement method *resolution*. Whether or not the returned method is
+ * actually invoked at runtime depends on the invocation instruction and the class hierarchy, so
+ * the users (e.g. the inliner) have to be aware of method selection.
+ *
+ * Note that the returned method may be abstract (ACC_ABSTRACT), native (ACC_NATIVE) or signature
+ * polymorphic (methods `invoke` and `invokeExact` in class `MehtodHandles`).
*
* @return The [[MethodNode]] of the requested method and the [[InternalName]] of its declaring
- * class, or an error message if the method could not be found.
+ * class, or an error message if the method could not be found. An error message is also
+ * returned if method resolution results in multiple default methods.
*/
def methodNode(ownerInternalNameOrArrayDescriptor: String, name: String, descriptor: String): Either[MethodNotFound, (MethodNode, InternalName)] = {
- // on failure, returns a list of class names that could not be found on the classpath
- def methodNodeImpl(ownerInternalName: InternalName): Either[List[ClassNotFound], (MethodNode, InternalName)] = {
- classNode(ownerInternalName) match {
- case Left(e) => Left(List(e))
- case Right(c) =>
- c.methods.asScala.find(m => m.name == name && m.desc == descriptor) match {
- case Some(m) => Right((m, ownerInternalName))
- case None => findInParents(Option(c.superName) ++: c.interfaces.asScala.toList, Nil)
- }
+ def findMethod(c: ClassNode): Option[MethodNode] = c.methods.asScala.find(m => m.name == name && m.desc == descriptor)
+
+ // https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.9: "In Java SE 8, the only
+ // signature polymorphic methods are the invoke and invokeExact methods of the class MethodHandle.
+ def isSignaturePolymorphic(owner: InternalName) = owner == coreBTypes.jliMethodHandleRef.internalName && (name == "invoke" || name == "invokeExact")
+
+ // Note: if `owner` is an interface, in the first iteration we search for a matching member in the interface itself.
+ // If that fails, the recursive invocation checks in the superclass (which is Object) with `publicInstanceOnly == true`.
+ // This is specified in jvms-5.4.3.4: interface method resolution only returns public, non-static methods of Object.
+ def findInSuperClasses(owner: ClassNode, publicInstanceOnly: Boolean = false): Either[ClassNotFound, Option[(MethodNode, InternalName)]] = {
+ findMethod(owner) match {
+ case Some(m) if !publicInstanceOnly || (isPublicMethod(m) && !isStaticMethod(m)) => Right(Some((m, owner.name)))
+ case None =>
+ if (isSignaturePolymorphic(owner.name)) Right(Some((owner.methods.asScala.find(_.name == name).get, owner.name)))
+ else if (owner.superName == null) Right(None)
+ else classNode(owner.superName).flatMap(findInSuperClasses(_, isInterface(owner)))
}
}
- // find the MethodNode in one of the parent classes
- def findInParents(parents: List[InternalName], failedClasses: List[ClassNotFound]): Either[List[ClassNotFound], (MethodNode, InternalName)] = parents match {
- case x :: xs => methodNodeImpl(x).left.flatMap(failed => findInParents(xs, failed ::: failedClasses))
- case Nil => Left(failedClasses)
+ def findInInterfaces(initialOwner: ClassNode): Either[ClassNotFound, Option[(MethodNode, InternalName)]] = {
+ val visited = mutable.Set.empty[InternalName]
+ val found = mutable.ListBuffer.empty[(MethodNode, ClassNode)]
+
+ def findIn(owner: ClassNode): Option[ClassNotFound] = {
+ for (i <- owner.interfaces.asScala if !visited(i)) classNode(i) match {
+ case Left(e) => return Some(e)
+ case Right(c) =>
+ visited += i
+ // abstract and static methods are excluded, see jvms-5.4.3.3
+ for (m <- findMethod(c) if !isPrivateMethod(m) && !isStaticMethod(m)) found += ((m, c))
+ val recusionResult = findIn(c)
+ if (recusionResult.isDefined) return recusionResult
+ }
+ None
+ }
+
+ findIn(initialOwner)
+
+ val result =
+ if (found.size <= 1) found.headOption
+ else {
+ val maxSpecific = found.filterNot({
+ case (method, owner) =>
+ isAbstractMethod(method) || {
+ val ownerTp = classBTypeFromClassNode(owner)
+ found exists {
+ case (other, otherOwner) =>
+ (other ne method) && {
+ val otherTp = classBTypeFromClassNode(otherOwner)
+ otherTp.isSubtypeOf(ownerTp).get
+ }
+ }
+ }
+ })
+ // (*) note that if there's no single, non-abstract, maximally-specific method, the jvm
+ // method resolution (jvms-5.4.3.3) returns any of the non-private, non-static parent
+ // methods at random (abstract or concrete).
+ // we chose not to do this here, to prevent the inliner from potentially inlining the
+ // wrong method. in other words, we guarantee that a concrete method is only returned if
+ // it resolves deterministically.
+ // however, there may be multiple abstract methods inherited. in this case we *do* want
+ // to return a result to allow performing accessibility checks in the inliner. note that
+ // for accessibility it does not matter which of these methods is return, as they are all
+ // non-private (i.e., public, protected is not possible, jvms-4.1).
+ // the remaining case (when there's no max-specific method, but some non-abstract one)
+ // does not occur in bytecode generated by scalac or javac. we return no result in this
+ // case. this may at worst prevent some optimizations from happening.
+ if (maxSpecific.size == 1) maxSpecific.headOption
+ else if (found.forall(p => isAbstractMethod(p._1))) found.headOption // (*)
+ else None
+ }
+ Right(result.map(p => (p._1, p._2.name)))
}
// In a MethodInsnNode, the `owner` field may be an array descriptor, for example when invoking `clone`. We don't have a method node to return in this case.
- if (ownerInternalNameOrArrayDescriptor.charAt(0) == '[')
- Left(MethodNotFound(name, descriptor, ownerInternalNameOrArrayDescriptor, Nil))
- else
- methodNodeImpl(ownerInternalNameOrArrayDescriptor).left.map(MethodNotFound(name, descriptor, ownerInternalNameOrArrayDescriptor, _))
+ if (ownerInternalNameOrArrayDescriptor.charAt(0) == '[') {
+ Left(MethodNotFound(name, descriptor, ownerInternalNameOrArrayDescriptor, None))
+ } else {
+ def notFound(cnf: Option[ClassNotFound]) = Left(MethodNotFound(name, descriptor, ownerInternalNameOrArrayDescriptor, cnf))
+ val res: Either[ClassNotFound, Option[(MethodNode, InternalName)]] = classNode(ownerInternalNameOrArrayDescriptor).flatMap(c =>
+ findInSuperClasses(c) flatMap {
+ case None => findInInterfaces(c)
+ case res => Right(res)
+ }
+ )
+ res match {
+ case Left(e) => notFound(Some(e))
+ case Right(None) => notFound(None)
+ case Right(Some(res)) => Right(res)
+ }
+ }
}
private def parseClass(internalName: InternalName): Either[ClassNotFound, ClassNode] = {
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala
index 2afc095af6..63906d80e5 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala
@@ -17,7 +17,7 @@ import scala.tools.asm.{Label, Type}
import scala.tools.asm.Opcodes._
import scala.tools.asm.tree._
import GenBCode._
-import scala.collection.convert.decorateAsScala._
+import scala.collection.JavaConverters._
import scala.tools.nsc.backend.jvm.analysis.InstructionStackEffect
object BytecodeUtils {
@@ -99,6 +99,10 @@ object BytecodeUtils {
methodNode.name == INSTANCE_CONSTRUCTOR_NAME || methodNode.name == CLASS_CONSTRUCTOR_NAME
}
+ def isPublicMethod(methodNode: MethodNode): Boolean = (methodNode.access & ACC_PUBLIC) != 0
+
+ def isPrivateMethod(methodNode: MethodNode): Boolean = (methodNode.access & ACC_PRIVATE) != 0
+
def isStaticMethod(methodNode: MethodNode): Boolean = (methodNode.access & ACC_STATIC) != 0
def isAbstractMethod(methodNode: MethodNode): Boolean = (methodNode.access & ACC_ABSTRACT) != 0
@@ -107,10 +111,12 @@ object BytecodeUtils {
def isNativeMethod(methodNode: MethodNode): Boolean = (methodNode.access & ACC_NATIVE) != 0
- def hasCallerSensitiveAnnotation(methodNode: MethodNode) = methodNode.visibleAnnotations != null && methodNode.visibleAnnotations.asScala.exists(_.desc == "Lsun/reflect/CallerSensitive;")
+ def hasCallerSensitiveAnnotation(methodNode: MethodNode): Boolean = methodNode.visibleAnnotations != null && methodNode.visibleAnnotations.asScala.exists(_.desc == "Lsun/reflect/CallerSensitive;")
def isFinalClass(classNode: ClassNode): Boolean = (classNode.access & ACC_FINAL) != 0
+ def isInterface(classNode: ClassNode): Boolean = (classNode.access & ACC_INTERFACE) != 0
+
def isFinalMethod(methodNode: MethodNode): Boolean = (methodNode.access & (ACC_FINAL | ACC_PRIVATE | ACC_STATIC)) != 0
def isStrictfpMethod(methodNode: MethodNode): Boolean = (methodNode.access & ACC_STRICT) != 0
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
index 5f06e13560..d241acf7b1 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
@@ -12,7 +12,7 @@ import scala.reflect.internal.util.{NoPosition, Position}
import scala.tools.asm.{Opcodes, Type, Handle}
import scala.tools.asm.tree._
import scala.collection.{concurrent, mutable}
-import scala.collection.convert.decorateAsScala._
+import scala.collection.JavaConverters._
import scala.tools.nsc.backend.jvm.BTypes.InternalName
import scala.tools.nsc.backend.jvm.BackendReporting._
import scala.tools.nsc.backend.jvm.analysis._
@@ -131,19 +131,19 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
(method, declarationClass) <- byteCodeRepository.methodNode(call.owner, call.name, call.desc): Either[OptimizerWarning, (MethodNode, InternalName)]
(declarationClassNode, source) <- byteCodeRepository.classNodeAndSource(declarationClass): Either[OptimizerWarning, (ClassNode, Source)]
} yield {
- val declarationClassBType = classBTypeFromClassNode(declarationClassNode)
- val info = analyzeCallsite(method, declarationClassBType, call, source)
- import info._
- Callee(
- callee = method,
- calleeDeclarationClass = declarationClassBType,
- safeToInline = safeToInline,
- canInlineFromSource = canInlineFromSource,
- annotatedInline = annotatedInline,
- annotatedNoInline = annotatedNoInline,
- samParamTypes = info.samParamTypes,
- calleeInfoWarning = warning)
- }
+ val declarationClassBType = classBTypeFromClassNode(declarationClassNode)
+ val info = analyzeCallsite(method, declarationClassBType, call, source)
+ import info._
+ Callee(
+ callee = method,
+ calleeDeclarationClass = declarationClassBType,
+ safeToInline = safeToInline,
+ canInlineFromSource = canInlineFromSource,
+ annotatedInline = annotatedInline,
+ annotatedNoInline = annotatedNoInline,
+ samParamTypes = info.samParamTypes,
+ calleeInfoWarning = warning)
+ }
val argInfos = computeArgInfos(callee, call, prodCons)
@@ -388,12 +388,11 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
* @param calleeInfoWarning An inliner warning if some information was not available while
* gathering the information about this callee.
*/
- final case class Callee(
- callee: MethodNode, calleeDeclarationClass: btypes.ClassBType,
- safeToInline: Boolean, canInlineFromSource: Boolean,
- annotatedInline: Boolean, annotatedNoInline: Boolean,
- samParamTypes: IntMap[btypes.ClassBType],
- calleeInfoWarning: Option[CalleeInfoWarning]) {
+ final case class Callee(callee: MethodNode, calleeDeclarationClass: btypes.ClassBType,
+ safeToInline: Boolean, canInlineFromSource: Boolean,
+ annotatedInline: Boolean, annotatedNoInline: Boolean,
+ samParamTypes: IntMap[btypes.ClassBType],
+ calleeInfoWarning: Option[CalleeInfoWarning]) {
override def toString = s"Callee($calleeDeclarationClass.${callee.name})"
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala
index dcfa9ef705..93dc40f318 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala
@@ -18,7 +18,7 @@ import BytecodeUtils._
import BackendReporting._
import Opcodes._
import scala.tools.nsc.backend.jvm.opt.ByteCodeRepository.CompilationUnit
-import scala.collection.convert.decorateAsScala._
+import scala.collection.JavaConverters._
class ClosureOptimizer[BT <: BTypes](val btypes: BT) {
import btypes._
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/CopyProp.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/CopyProp.scala
index d28565b9bc..4163d62df7 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/CopyProp.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/CopyProp.scala
@@ -13,7 +13,7 @@ import scala.tools.asm.Type
import scala.tools.asm.Opcodes._
import scala.tools.asm.tree._
import scala.collection.mutable
-import scala.collection.convert.decorateAsScala._
+import scala.collection.JavaConverters._
import scala.tools.nsc.backend.jvm.BTypes.InternalName
import scala.tools.nsc.backend.jvm.analysis._
import scala.tools.nsc.backend.jvm.opt.BytecodeUtils._
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/InlineInfoAttribute.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/InlineInfoAttribute.scala
index 079a9eec9b..79d26b0b4e 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/InlineInfoAttribute.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/InlineInfoAttribute.scala
@@ -47,11 +47,12 @@ case class InlineInfoAttribute(inlineInfo: InlineInfo) extends Attribute(InlineI
result.putByte(InlineInfoAttribute.VERSION)
- var finalSelfSam = 0
- if (inlineInfo.isEffectivelyFinal) finalSelfSam |= 1
- // finalSelfSam |= 2 // no longer written
- if (inlineInfo.sam.isDefined) finalSelfSam |= 4
- result.putByte(finalSelfSam)
+ var flags = 0
+ if (inlineInfo.isEffectivelyFinal) flags |= 1
+ // flags |= 2 // no longer written
+ if (inlineInfo.sam.isDefined) flags |= 4
+ if (inlineInfo.lateInterfaces.nonEmpty) flags |= 8
+ result.putByte(flags)
for (samNameDesc <- inlineInfo.sam) {
val (name, desc) = samNameDesc.span(_ != '(')
@@ -78,6 +79,9 @@ case class InlineInfoAttribute(inlineInfo: InlineInfo) extends Attribute(InlineI
result.putByte(inlineInfo)
}
+ result.putShort(inlineInfo.lateInterfaces.length)
+ for (i <- inlineInfo.lateInterfaces) result.putShort(cw.newUTF8(i))
+
result
}
@@ -97,10 +101,11 @@ case class InlineInfoAttribute(inlineInfo: InlineInfo) extends Attribute(InlineI
val version = nextByte()
if (version == 1) {
- val finalSelfSam = nextByte()
- val isFinal = (finalSelfSam & 1) != 0
- val hasSelf = (finalSelfSam & 2) != 0
- val hasSam = (finalSelfSam & 4) != 0
+ val flags = nextByte()
+ val isFinal = (flags & 1) != 0
+ val hasSelf = (flags & 2) != 0
+ val hasSam = (flags & 4) != 0
+ val hasLateInterfaces = (flags & 8) != 0
if (hasSelf) nextUTF8() // no longer used
@@ -116,14 +121,21 @@ case class InlineInfoAttribute(inlineInfo: InlineInfo) extends Attribute(InlineI
val desc = nextUTF8()
val inlineInfo = nextByte()
- val isFinal = (inlineInfo & 1) != 0
- // val traitMethodWithStaticImplementation = (inlineInfo & 2) != 0 // no longer used
- val isInline = (inlineInfo & 4) != 0
- val isNoInline = (inlineInfo & 8) != 0
+ val isFinal = (inlineInfo & 1) != 0
+ // = (inlineInfo & 2) != 0 // no longer used
+ val isInline = (inlineInfo & 4) != 0
+ val isNoInline = (inlineInfo & 8) != 0
(name + desc, MethodInlineInfo(isFinal, isInline, isNoInline))
}).toMap
- InlineInfoAttribute(InlineInfo(isFinal, sam, infos, None))
+ val lateInterfaces = if (!hasLateInterfaces) Nil else {
+ val numLateInterfaces = nextShort()
+ (0 until numLateInterfaces).map(_ => nextUTF8())
+ }
+
+ val info = InlineInfo(isFinal, sam, infos, None)
+ info.lateInterfaces ++= lateInterfaces
+ InlineInfoAttribute(info)
} else {
val msg = UnknownScalaInlineInfoVersion(cr.getClassName, version)
InlineInfoAttribute(BTypes.EmptyInlineInfo.copy(warning = Some(msg)))
@@ -141,7 +153,7 @@ object InlineInfoAttribute {
* is ignored.
*
* [u1] version
- * [u1] isEffectivelyFinal (<< 0), hasTraitImplClassSelfType (<< 1), hasSam (<< 2)
+ * [u1] isEffectivelyFinal (<< 0), hasTraitImplClassSelfType (<< 1), hasSam (<< 2), hasLateInterfaces (<< 3)
* [u2]? traitImplClassSelfType (reference)
* [u2]? samName (reference)
* [u2]? samDescriptor (reference)
@@ -149,6 +161,8 @@ object InlineInfoAttribute {
* [u2] name (reference)
* [u2] descriptor (reference)
* [u1] isFinal (<< 0), traitMethodWithStaticImplementation (<< 1), hasInlineAnnotation (<< 2), hasNoInlineAnnotation (<< 3)
+ * [u2]? numLateInterfaces
+ * [u2] lateInterface (reference)
*/
final val VERSION: Byte = 1
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
index a0ef74b46a..f35eaa45e9 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
@@ -11,8 +11,7 @@ import scala.annotation.tailrec
import scala.tools.asm
import asm.Opcodes._
import asm.tree._
-import scala.collection.convert.decorateAsScala._
-import scala.collection.convert.decorateAsJava._
+import scala.collection.JavaConverters._
import AsmUtils._
import BytecodeUtils._
import collection.mutable
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala
index e132ae1792..6aaf9734d3 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala
@@ -9,7 +9,7 @@ package opt
import scala.tools.asm.tree.MethodNode
import scala.tools.nsc.backend.jvm.BTypes.InternalName
-import scala.collection.convert.decorateAsScala._
+import scala.collection.JavaConverters._
import scala.tools.nsc.backend.jvm.BackendReporting.OptimizerWarning
class InlinerHeuristics[BT <: BTypes](val bTypes: BT) {
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala
index f120357c63..4e1349257e 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala
@@ -14,7 +14,7 @@ import scala.tools.asm.tree.analysis.Frame
import scala.tools.asm.Opcodes._
import scala.tools.asm.tree._
import scala.collection.mutable
-import scala.collection.convert.decorateAsScala._
+import scala.collection.JavaConverters._
import scala.tools.nsc.backend.jvm.BTypes.InternalName
import scala.tools.nsc.backend.jvm.analysis._
import scala.tools.nsc.backend.jvm.opt.BytecodeUtils._
diff --git a/src/compiler/scala/tools/nsc/classpath/AggregateFlatClassPath.scala b/src/compiler/scala/tools/nsc/classpath/AggregateClassPath.scala
index f97d97548e..a1af3413ea 100644
--- a/src/compiler/scala/tools/nsc/classpath/AggregateFlatClassPath.scala
+++ b/src/compiler/scala/tools/nsc/classpath/AggregateClassPath.scala
@@ -6,21 +6,23 @@ 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
/**
* A classpath unifying multiple class- and sourcepath entries.
- * Flat classpath can obtain entries for classes and sources independently
+ * The Classpath can obtain entries for classes and sources independently
* so it tries to do operations quite optimally - iterating only these collections
* which are needed in the given moment and only as far as it's necessary.
+ *
* @param aggregates classpath instances containing entries which this class processes
*/
-case class AggregateFlatClassPath(aggregates: Seq[FlatClassPath]) extends FlatClassPath {
+case class AggregateClassPath(aggregates: Seq[ClassPath]) extends ClassPath {
override def findClassFile(className: String): Option[AbstractFile] = {
@tailrec
- def find(aggregates: Seq[FlatClassPath]): Option[AbstractFile] =
+ def find(aggregates: Seq[ClassPath]): Option[AbstractFile] =
if (aggregates.nonEmpty) {
val classFile = aggregates.head.findClassFile(className)
if (classFile.isDefined) classFile
@@ -30,22 +32,24 @@ case class AggregateFlatClassPath(aggregates: Seq[FlatClassPath]) extends FlatCl
find(aggregates)
}
- override def findClass(className: String): Option[ClassRepresentation[AbstractFile]] = {
- val (pkg, simpleClassName) = PackageNameUtils.separatePkgAndClassNames(className)
-
+ override def findClass(className: String): Option[ClassRepresentation] = {
@tailrec
- def findEntry[T <: ClassRepClassPathEntry](aggregates: Seq[FlatClassPath], getEntries: FlatClassPath => Seq[T]): Option[T] =
+ def findEntry(aggregates: Seq[ClassPath], isSource: Boolean): Option[ClassRepresentation] =
if (aggregates.nonEmpty) {
- val entry = getEntries(aggregates.head).find(_.name == simpleClassName)
+ val entry = aggregates.head.findClass(className) match {
+ case s @ Some(_: SourceFileEntry) if isSource => s
+ case s @ Some(_: ClassFileEntry) if !isSource => s
+ case _ => None
+ }
if (entry.isDefined) entry
- else findEntry(aggregates.tail, getEntries)
+ else findEntry(aggregates.tail, isSource)
} else None
- val classEntry = findEntry(aggregates, classesGetter(pkg))
- val sourceEntry = findEntry(aggregates, sourcesGetter(pkg))
+ val classEntry = findEntry(aggregates, isSource = false)
+ val sourceEntry = findEntry(aggregates, isSource = true)
(classEntry, sourceEntry) match {
- case (Some(c), Some(s)) => Some(ClassAndSourceFilesEntry(c.file, s.file))
+ case (Some(c: ClassFileEntry), Some(s: SourceFileEntry)) => Some(ClassAndSourceFilesEntry(c.file, s.file))
case (c @ Some(_), _) => c
case (_, s) => s
}
@@ -63,16 +67,25 @@ case class AggregateFlatClassPath(aggregates: Seq[FlatClassPath]) extends FlatCl
}
override private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] =
- getDistinctEntries(classesGetter(inPackage))
+ getDistinctEntries(_.classes(inPackage))
override private[nsc] def sources(inPackage: String): Seq[SourceFileEntry] =
- getDistinctEntries(sourcesGetter(inPackage))
-
- override private[nsc] def list(inPackage: String): FlatClassPathEntries = {
- val (packages, classesAndSources) = aggregates.map(_.list(inPackage)).unzip
+ getDistinctEntries(_.sources(inPackage))
+
+ override private[nsc] def list(inPackage: String): ClassPathEntries = {
+ 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: _*)
- FlatClassPathEntries(distinctPackages, distinctClassesAndSources)
+ ClassPathEntries(distinctPackages, distinctClassesAndSources)
}
/**
@@ -80,11 +93,11 @@ case class AggregateFlatClassPath(aggregates: Seq[FlatClassPath]) extends FlatCl
* creates an entry containing both of them. If there would be more than one class or source
* entries for the same class it always would use the first entry of each type found on a classpath.
*/
- private def mergeClassesAndSources(entries: Seq[ClassRepClassPathEntry]*): Seq[ClassRepClassPathEntry] = {
+ private def mergeClassesAndSources(entries: Seq[ClassRepresentation]*): Seq[ClassRepresentation] = {
// based on the implementation from MergedClassPath
var count = 0
val indices = collection.mutable.HashMap[String, Int]()
- val mergedEntries = new ArrayBuffer[ClassRepClassPathEntry](1024)
+ val mergedEntries = new ArrayBuffer[ClassRepresentation](1024)
for {
partOfEntries <- entries
@@ -109,7 +122,7 @@ case class AggregateFlatClassPath(aggregates: Seq[FlatClassPath]) extends FlatCl
mergedEntries.toIndexedSeq
}
- private def getDistinctEntries[EntryType <: ClassRepClassPathEntry](getEntries: FlatClassPath => Seq[EntryType]): Seq[EntryType] = {
+ private def getDistinctEntries[EntryType <: ClassRepresentation](getEntries: ClassPath => Seq[EntryType]): Seq[EntryType] = {
val seenNames = collection.mutable.HashSet[String]()
val entriesBuffer = new ArrayBuffer[EntryType](1024)
for {
@@ -121,19 +134,16 @@ case class AggregateFlatClassPath(aggregates: Seq[FlatClassPath]) extends FlatCl
}
entriesBuffer.toIndexedSeq
}
-
- private def classesGetter(pkg: String) = (cp: FlatClassPath) => cp.classes(pkg)
- private def sourcesGetter(pkg: String) = (cp: FlatClassPath) => cp.sources(pkg)
}
-object AggregateFlatClassPath {
- def createAggregate(parts: FlatClassPath*): FlatClassPath = {
- val elems = new ArrayBuffer[FlatClassPath]()
+object AggregateClassPath {
+ def createAggregate(parts: ClassPath*): ClassPath = {
+ val elems = new ArrayBuffer[ClassPath]()
parts foreach {
- case AggregateFlatClassPath(ps) => elems ++= ps
+ case AggregateClassPath(ps) => elems ++= ps
case p => elems += p
}
if (elems.size == 1) elems.head
- else AggregateFlatClassPath(elems.toIndexedSeq)
+ else AggregateClassPath(elems.toIndexedSeq)
}
}
diff --git a/src/compiler/scala/tools/nsc/classpath/ClassPath.scala b/src/compiler/scala/tools/nsc/classpath/ClassPath.scala
new file mode 100644
index 0000000000..08bd98b1d8
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/classpath/ClassPath.scala
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014 Contributor. All rights reserved.
+ */
+package scala.tools.nsc.classpath
+
+import scala.reflect.io.AbstractFile
+import scala.tools.nsc.util.ClassRepresentation
+
+case class ClassPathEntries(packages: Seq[PackageEntry], classesAndSources: Seq[ClassRepresentation])
+
+object ClassPathEntries {
+ import scala.language.implicitConversions
+ // to have working unzip method
+ implicit def entry2Tuple(entry: ClassPathEntries): (Seq[PackageEntry], Seq[ClassRepresentation]) = (entry.packages, entry.classesAndSources)
+}
+
+trait ClassFileEntry extends ClassRepresentation {
+ def file: AbstractFile
+}
+
+trait SourceFileEntry extends ClassRepresentation {
+ def file: AbstractFile
+}
+
+trait PackageEntry {
+ def name: String
+}
+
+private[nsc] case class ClassFileEntryImpl(file: AbstractFile) extends ClassFileEntry {
+ override def name = FileUtils.stripClassExtension(file.name) // class name
+
+ override def binary: Option[AbstractFile] = Some(file)
+ override def source: Option[AbstractFile] = None
+}
+
+private[nsc] case class SourceFileEntryImpl(file: AbstractFile) extends SourceFileEntry {
+ override def name = FileUtils.stripSourceExtension(file.name)
+
+ override def binary: Option[AbstractFile] = None
+ override def source: Option[AbstractFile] = Some(file)
+}
+
+private[nsc] case class ClassAndSourceFilesEntry(classFile: AbstractFile, srcFile: AbstractFile) extends ClassRepresentation {
+ override def name = FileUtils.stripClassExtension(classFile.name)
+
+ override def binary: Option[AbstractFile] = Some(classFile)
+ override def source: Option[AbstractFile] = Some(srcFile)
+}
+
+private[nsc] case class PackageEntryImpl(name: String) extends PackageEntry
+
+private[nsc] trait NoSourcePaths {
+ def asSourcePathString: String = ""
+ private[nsc] def sources(inPackage: String): Seq[SourceFileEntry] = Seq.empty
+}
+
+private[nsc] trait NoClassPaths {
+ def findClassFile(className: String): Option[AbstractFile] = None
+ private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = Seq.empty
+}
diff --git a/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala b/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala
index 9bf4e3f779..3a29f1ba11 100644
--- a/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala
+++ b/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala
@@ -3,47 +3,49 @@
*/
package scala.tools.nsc.classpath
-import scala.reflect.io.AbstractFile
+import scala.reflect.io.{AbstractFile, VirtualDirectory}
+import scala.tools.nsc.Settings
+import FileUtils.AbstractFileOps
import scala.tools.nsc.util.ClassPath
/**
- * A trait that contains factory methods for classpath elements of type T.
- *
- * The logic has been abstracted from ClassPath#ClassPathContext so it's possible
- * to have common trait that supports both recursive and flat classpath representations.
- *
- * Therefore, we expect that T will be either ClassPath[U] or FlatClassPath.
+ * Provides factory methods for classpath. When creating classpath instances for a given path,
+ * it uses proper type of classpath depending on a types of particular files containing sources or classes.
*/
-trait ClassPathFactory[T] {
-
+class ClassPathFactory(settings: Settings) {
/**
- * Create a new classpath based on the abstract file.
- */
- def newClassPath(file: AbstractFile): T
+ * Create a new classpath based on the abstract file.
+ */
+ def newClassPath(file: AbstractFile): ClassPath = ClassPathFactory.newClassPath(file, settings)
/**
- * Creators for sub classpaths which preserve this context.
- */
- def sourcesInPath(path: String): List[T]
+ * Creators for sub classpaths which preserve this context.
+ */
+ def sourcesInPath(path: String): List[ClassPath] =
+ for {
+ file <- expandPath(path, expandStar = false)
+ dir <- Option(AbstractFile getDirectory file)
+ } yield createSourcePath(dir)
+
- def expandPath(path: String, expandStar: Boolean = true): List[String] = ClassPath.expandPath(path, expandStar)
+ def expandPath(path: String, expandStar: Boolean = true): List[String] = scala.tools.nsc.util.ClassPath.expandPath(path, expandStar)
- def expandDir(extdir: String): List[String] = ClassPath.expandDir(extdir)
+ def expandDir(extdir: String): List[String] = scala.tools.nsc.util.ClassPath.expandDir(extdir)
- def contentsOfDirsInPath(path: String): List[T] =
+ def contentsOfDirsInPath(path: String): List[ClassPath] =
for {
dir <- expandPath(path, expandStar = false)
name <- expandDir(dir)
entry <- Option(AbstractFile.getDirectory(name))
} yield newClassPath(entry)
- def classesInExpandedPath(path: String): IndexedSeq[T] =
+ def classesInExpandedPath(path: String): IndexedSeq[ClassPath] =
classesInPathImpl(path, expand = true).toIndexedSeq
def classesInPath(path: String) = classesInPathImpl(path, expand = false)
def classesInManifest(useManifestClassPath: Boolean) =
- if (useManifestClassPath) ClassPath.manifests.map(url => newClassPath(AbstractFile getResources url))
+ if (useManifestClassPath) scala.tools.nsc.util.ClassPath.manifests.map(url => newClassPath(AbstractFile getResources url))
else Nil
// Internal
@@ -52,4 +54,25 @@ trait ClassPathFactory[T] {
file <- expandPath(path, expand)
dir <- Option(AbstractFile.getDirectory(file))
} yield newClassPath(dir)
+
+ private def createSourcePath(file: AbstractFile): ClassPath =
+ if (file.isJarOrZip)
+ ZipAndJarSourcePathFactory.create(file, settings)
+ else if (file.isDirectory)
+ new DirectorySourcePath(file.file)
+ else
+ sys.error(s"Unsupported sourcepath element: $file")
+}
+
+object ClassPathFactory {
+ def newClassPath(file: AbstractFile, settings: Settings): ClassPath = file match {
+ case vd: VirtualDirectory => VirtualDirectoryClassPath(vd)
+ case _ =>
+ if (file.isJarOrZip)
+ ZipAndJarClassPathFactory.create(file, settings)
+ else if (file.isDirectory)
+ new DirectoryClassPath(file.file)
+ else
+ sys.error(s"Unsupported classpath element: $file")
+ }
}
diff --git a/src/compiler/scala/tools/nsc/classpath/DirectoryFlatClassPath.scala b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala
index e3964dfa78..aba941e043 100644
--- a/src/compiler/scala/tools/nsc/classpath/DirectoryFlatClassPath.scala
+++ b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala
@@ -5,9 +5,8 @@ package scala.tools.nsc.classpath
import java.io.File
import java.net.URL
-import scala.reflect.io.AbstractFile
-import scala.reflect.io.PlainFile
-import scala.tools.nsc.util.ClassRepresentation
+import scala.reflect.io.{AbstractFile, PlainFile}
+import scala.tools.nsc.util.{ClassPath, ClassRepresentation}
import FileUtils._
/**
@@ -17,7 +16,7 @@ import FileUtils._
* when we have a name of a package.
* It abstracts over the file representation to work with both JFile and AbstractFile.
*/
-trait DirectoryLookup[FileEntryType <: ClassRepClassPathEntry] extends FlatClassPath {
+trait DirectoryLookup[FileEntryType <: ClassRepresentation] extends ClassPath {
type F
val dir: F
@@ -33,7 +32,7 @@ trait DirectoryLookup[FileEntryType <: ClassRepClassPathEntry] extends FlatClass
protected def isMatchingFile(f: F): Boolean
private def getDirectory(forPackage: String): Option[F] = {
- if (forPackage == FlatClassPath.RootPackage) {
+ if (forPackage == ClassPath.RootPackage) {
Some(dir)
} else {
val packageDirName = FileUtils.dirPath(forPackage)
@@ -60,7 +59,7 @@ trait DirectoryLookup[FileEntryType <: ClassRepClassPathEntry] extends FlatClass
files.map(f => createFileEntry(toAbstractFile(f)))
}
- private[nsc] def list(inPackage: String): FlatClassPathEntries = {
+ private[nsc] def list(inPackage: String): ClassPathEntries = {
val dirForPackage = getDirectory(inPackage)
val files: Array[F] = dirForPackage match {
case None => emptyFiles
@@ -75,11 +74,11 @@ trait DirectoryLookup[FileEntryType <: ClassRepClassPathEntry] extends FlatClass
else if (isMatchingFile(file))
fileBuf += createFileEntry(toAbstractFile(file))
}
- FlatClassPathEntries(packageBuf, fileBuf)
+ ClassPathEntries(packageBuf, fileBuf)
}
}
-trait JFileDirectoryLookup[FileEntryType <: ClassRepClassPathEntry] extends DirectoryLookup[FileEntryType] {
+trait JFileDirectoryLookup[FileEntryType <: ClassRepresentation] extends DirectoryLookup[FileEntryType] {
type F = File
protected def emptyFiles: Array[File] = Array.empty
@@ -102,8 +101,8 @@ trait JFileDirectoryLookup[FileEntryType <: ClassRepClassPathEntry] extends Dire
def asClassPathStrings: Seq[String] = Seq(dir.getPath)
}
-case class DirectoryFlatClassPath(dir: File) extends JFileDirectoryLookup[ClassFileEntryImpl] with NoSourcePaths {
- override def findClass(className: String): Option[ClassRepresentation[AbstractFile]] = findClassFile(className) map ClassFileEntryImpl
+case class DirectoryClassPath(dir: File) extends JFileDirectoryLookup[ClassFileEntryImpl] with NoSourcePaths {
+ override def findClass(className: String): Option[ClassRepresentation] = findClassFile(className) map ClassFileEntryImpl
def findClassFile(className: String): Option[AbstractFile] = {
val relativePath = FileUtils.dirPath(className)
@@ -121,13 +120,13 @@ case class DirectoryFlatClassPath(dir: File) extends JFileDirectoryLookup[ClassF
private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = files(inPackage)
}
-case class DirectoryFlatSourcePath(dir: File) extends JFileDirectoryLookup[SourceFileEntryImpl] with NoClassPaths {
+case class DirectorySourcePath(dir: File) extends JFileDirectoryLookup[SourceFileEntryImpl] with NoClassPaths {
def asSourcePathString: String = asClassPathString
protected def createFileEntry(file: AbstractFile): SourceFileEntryImpl = SourceFileEntryImpl(file)
protected def isMatchingFile(f: File): Boolean = endsScalaOrJava(f.getName)
- override def findClass(className: String): Option[ClassRepresentation[AbstractFile]] = findSourceFile(className) map SourceFileEntryImpl
+ override def findClass(className: String): Option[ClassRepresentation] = findSourceFile(className) map SourceFileEntryImpl
private def findSourceFile(className: String): Option[AbstractFile] = {
val relativePath = FileUtils.dirPath(className)
diff --git a/src/compiler/scala/tools/nsc/classpath/FlatClassPath.scala b/src/compiler/scala/tools/nsc/classpath/FlatClassPath.scala
deleted file mode 100644
index e95ffe02e3..0000000000
--- a/src/compiler/scala/tools/nsc/classpath/FlatClassPath.scala
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2014 Contributor. All rights reserved.
- */
-package scala.tools.nsc.classpath
-
-import scala.reflect.io.AbstractFile
-import scala.tools.nsc.util.{ ClassFileLookup, ClassPath, ClassRepresentation }
-
-/**
- * A base trait for the particular flat classpath representation implementations.
- *
- * We call this variant of a classpath representation flat because it's possible to
- * query the whole classpath using just single instance extending this trait.
- *
- * This is an alternative design compared to scala.tools.nsc.util.ClassPath
- */
-trait FlatClassPath extends ClassFileLookup[AbstractFile] {
- /** Empty string represents root package */
- private[nsc] def packages(inPackage: String): Seq[PackageEntry]
- private[nsc] def classes(inPackage: String): Seq[ClassFileEntry]
- private[nsc] def sources(inPackage: String): Seq[SourceFileEntry]
-
- /** Allows to get entries for packages and classes merged with sources possibly in one pass. */
- private[nsc] def list(inPackage: String): FlatClassPathEntries
-
- // A default implementation which should be overridden, if we can create the more efficient
- // solution for a given type of FlatClassPath
- override def findClass(className: String): Option[ClassRepresentation[AbstractFile]] = {
- val (pkg, simpleClassName) = PackageNameUtils.separatePkgAndClassNames(className)
-
- val foundClassFromClassFiles = classes(pkg).find(_.name == simpleClassName)
- def findClassInSources = sources(pkg).find(_.name == simpleClassName)
-
- foundClassFromClassFiles orElse findClassInSources
- }
-
- override def asClassPathString: String = ClassPath.join(asClassPathStrings: _*)
- def asClassPathStrings: Seq[String]
-}
-
-object FlatClassPath {
- val RootPackage = ""
-}
-
-case class FlatClassPathEntries(packages: Seq[PackageEntry], classesAndSources: Seq[ClassRepClassPathEntry])
-
-object FlatClassPathEntries {
- import scala.language.implicitConversions
- // to have working unzip method
- implicit def entry2Tuple(entry: FlatClassPathEntries): (Seq[PackageEntry], Seq[ClassRepClassPathEntry]) = (entry.packages, entry.classesAndSources)
-}
-
-sealed trait ClassRepClassPathEntry extends ClassRepresentation[AbstractFile]
-
-trait ClassFileEntry extends ClassRepClassPathEntry {
- def file: AbstractFile
-}
-
-trait SourceFileEntry extends ClassRepClassPathEntry {
- def file: AbstractFile
-}
-
-trait PackageEntry {
- def name: String
-}
-
-private[nsc] case class ClassFileEntryImpl(file: AbstractFile) extends ClassFileEntry {
- override def name = FileUtils.stripClassExtension(file.name) // class name
-
- override def binary: Option[AbstractFile] = Some(file)
- override def source: Option[AbstractFile] = None
-}
-
-private[nsc] case class SourceFileEntryImpl(file: AbstractFile) extends SourceFileEntry {
- override def name = FileUtils.stripSourceExtension(file.name)
-
- override def binary: Option[AbstractFile] = None
- override def source: Option[AbstractFile] = Some(file)
-}
-
-private[nsc] case class ClassAndSourceFilesEntry(classFile: AbstractFile, srcFile: AbstractFile) extends ClassRepClassPathEntry {
- override def name = FileUtils.stripClassExtension(classFile.name)
-
- override def binary: Option[AbstractFile] = Some(classFile)
- override def source: Option[AbstractFile] = Some(srcFile)
-}
-
-private[nsc] case class PackageEntryImpl(name: String) extends PackageEntry
-
-private[nsc] trait NoSourcePaths {
- def asSourcePathString: String = ""
- private[nsc] def sources(inPackage: String): Seq[SourceFileEntry] = Seq.empty
-}
-
-private[nsc] trait NoClassPaths {
- def findClassFile(className: String): Option[AbstractFile] = None
- private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = Seq.empty
-}
diff --git a/src/compiler/scala/tools/nsc/classpath/FlatClassPathFactory.scala b/src/compiler/scala/tools/nsc/classpath/FlatClassPathFactory.scala
deleted file mode 100644
index 463301696e..0000000000
--- a/src/compiler/scala/tools/nsc/classpath/FlatClassPathFactory.scala
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2014 Contributor. All rights reserved.
- */
-package scala.tools.nsc.classpath
-
-import scala.reflect.io.VirtualDirectory
-import scala.tools.nsc.Settings
-import scala.tools.nsc.io.AbstractFile
-import FileUtils.AbstractFileOps
-
-/**
- * Provides factory methods for flat classpath. When creating classpath instances for a given path,
- * it uses proper type of classpath depending on a types of particular files containing sources or classes.
- */
-class FlatClassPathFactory(settings: Settings) extends ClassPathFactory[FlatClassPath] {
- def newClassPath(file: AbstractFile): FlatClassPath = FlatClassPathFactory.newClassPath(file, settings)
-
- def sourcesInPath(path: String): List[FlatClassPath] =
- for {
- file <- expandPath(path, expandStar = false)
- dir <- Option(AbstractFile getDirectory file)
- } yield createSourcePath(dir)
-
- private def createSourcePath(file: AbstractFile): FlatClassPath =
- if (file.isJarOrZip)
- ZipAndJarFlatSourcePathFactory.create(file, settings)
- else if (file.isDirectory)
- new DirectoryFlatSourcePath(file.file)
- else
- sys.error(s"Unsupported sourcepath element: $file")
-}
-
-object FlatClassPathFactory {
- def newClassPath(file: AbstractFile, settings: Settings): FlatClassPath = file match {
- case vd: VirtualDirectory => VirtualDirectoryFlatClassPath(vd)
- case _ =>
- if (file.isJarOrZip)
- ZipAndJarFlatClassPathFactory.create(file, settings)
- else if (file.isDirectory)
- new DirectoryFlatClassPath(file.file)
- else
- sys.error(s"Unsupported classpath element: $file")
- }
-}
diff --git a/src/compiler/scala/tools/nsc/classpath/PackageNameUtils.scala b/src/compiler/scala/tools/nsc/classpath/PackageNameUtils.scala
index c907d565d2..39b0d78135 100644
--- a/src/compiler/scala/tools/nsc/classpath/PackageNameUtils.scala
+++ b/src/compiler/scala/tools/nsc/classpath/PackageNameUtils.scala
@@ -3,7 +3,7 @@
*/
package scala.tools.nsc.classpath
-import scala.tools.nsc.classpath.FlatClassPath.RootPackage
+import scala.tools.nsc.util.ClassPath.RootPackage
/**
* Common methods related to package names represented as String
diff --git a/src/compiler/scala/tools/nsc/classpath/VirtualDirectoryFlatClassPath.scala b/src/compiler/scala/tools/nsc/classpath/VirtualDirectoryClassPath.scala
index 06cdab583c..8df0c3743d 100644
--- a/src/compiler/scala/tools/nsc/classpath/VirtualDirectoryFlatClassPath.scala
+++ b/src/compiler/scala/tools/nsc/classpath/VirtualDirectoryClassPath.scala
@@ -4,8 +4,9 @@ import scala.tools.nsc.util.ClassRepresentation
import scala.reflect.io.{Path, PlainFile, VirtualDirectory, AbstractFile}
import FileUtils._
import java.net.URL
+import scala.tools.nsc.util.ClassPath
-case class VirtualDirectoryFlatClassPath(dir: VirtualDirectory) extends FlatClassPath with DirectoryLookup[ClassFileEntryImpl] with NoSourcePaths {
+case class VirtualDirectoryClassPath(dir: VirtualDirectory) extends ClassPath with DirectoryLookup[ClassFileEntryImpl] with NoSourcePaths {
type F = AbstractFile
protected def emptyFiles: Array[AbstractFile] = Array.empty
@@ -23,7 +24,7 @@ case class VirtualDirectoryFlatClassPath(dir: VirtualDirectory) extends FlatClas
def asURLs: Seq[URL] = Seq(new URL(dir.name))
def asClassPathStrings: Seq[String] = Seq(dir.path)
- override def findClass(className: String): Option[ClassRepresentation[AbstractFile]] = findClassFile(className) map ClassFileEntryImpl
+ override def findClass(className: String): Option[ClassRepresentation] = findClassFile(className) map ClassFileEntryImpl
def findClassFile(className: String): Option[AbstractFile] = {
val relativePath = FileUtils.dirPath(className)
diff --git a/src/compiler/scala/tools/nsc/classpath/ZipAndJarFileLookupFactory.scala b/src/compiler/scala/tools/nsc/classpath/ZipAndJarFileLookupFactory.scala
index 6ec3805d8b..fe74e5f874 100644
--- a/src/compiler/scala/tools/nsc/classpath/ZipAndJarFileLookupFactory.scala
+++ b/src/compiler/scala/tools/nsc/classpath/ZipAndJarFileLookupFactory.scala
@@ -6,7 +6,8 @@ package scala.tools.nsc.classpath
import java.io.File
import java.net.URL
import scala.annotation.tailrec
-import scala.reflect.io.{ AbstractFile, FileZipArchive, ManifestResources }
+import scala.reflect.io.{AbstractFile, FileZipArchive, ManifestResources}
+import scala.tools.nsc.util.ClassPath
import scala.tools.nsc.Settings
import FileUtils._
@@ -19,16 +20,16 @@ import FileUtils._
* when there are a lot of projects having a lot of common dependencies.
*/
sealed trait ZipAndJarFileLookupFactory {
- private val cache = collection.mutable.Map.empty[AbstractFile, FlatClassPath]
+ private val cache = collection.mutable.Map.empty[AbstractFile, ClassPath]
- def create(zipFile: AbstractFile, settings: Settings): FlatClassPath = {
+ def create(zipFile: AbstractFile, settings: Settings): ClassPath = {
if (settings.YdisableFlatCpCaching) createForZipFile(zipFile)
else createUsingCache(zipFile, settings)
}
- protected def createForZipFile(zipFile: AbstractFile): FlatClassPath
+ protected def createForZipFile(zipFile: AbstractFile): ClassPath
- private def createUsingCache(zipFile: AbstractFile, settings: Settings): FlatClassPath = cache.synchronized {
+ private def createUsingCache(zipFile: AbstractFile, settings: Settings): ClassPath = cache.synchronized {
def newClassPathInstance = {
if (settings.verbose || settings.Ylogcp)
println(s"$zipFile is not yet in the classpath cache")
@@ -39,11 +40,11 @@ sealed trait ZipAndJarFileLookupFactory {
}
/**
- * Manages creation of flat classpath for class files placed in zip and jar files.
+ * Manages creation of classpath for class files placed in zip and jar files.
* It should be the only way of creating them as it provides caching.
*/
-object ZipAndJarFlatClassPathFactory extends ZipAndJarFileLookupFactory {
- private case class ZipArchiveFlatClassPath(zipFile: File)
+object ZipAndJarClassPathFactory extends ZipAndJarFileLookupFactory {
+ private case class ZipArchiveClassPath(zipFile: File)
extends ZipArchiveFileLookup[ClassFileEntryImpl]
with NoSourcePaths {
@@ -65,7 +66,7 @@ object ZipAndJarFlatClassPathFactory extends ZipAndJarFileLookupFactory {
* with a particularly prepared scala-library.jar. It should have all classes listed in the manifest like e.g. this entry:
* Name: scala/Function2$mcFJD$sp.class
*/
- private case class ManifestResourcesFlatClassPath(file: ManifestResources) extends FlatClassPath with NoSourcePaths {
+ private case class ManifestResourcesClassPath(file: ManifestResources) extends ClassPath with NoSourcePaths {
override def findClassFile(className: String): Option[AbstractFile] = {
val (pkg, simpleClassName) = PackageNameUtils.separatePkgAndClassNames(className)
classes(pkg).find(_.name == simpleClassName).map(_.file)
@@ -75,8 +76,8 @@ object ZipAndJarFlatClassPathFactory extends ZipAndJarFileLookupFactory {
override def asURLs: Seq[URL] = file.toURLs()
- import ManifestResourcesFlatClassPath.PackageFileInfo
- import ManifestResourcesFlatClassPath.PackageInfo
+ import ManifestResourcesClassPath.PackageFileInfo
+ import ManifestResourcesClassPath.PackageInfo
/**
* A cache mapping package name to abstract file for package directory and subpackages of given package.
@@ -114,8 +115,8 @@ object ZipAndJarFlatClassPathFactory extends ZipAndJarFileLookupFactory {
}
val subpackages = getSubpackages(file)
- packages.put(FlatClassPath.RootPackage, PackageFileInfo(file, subpackages))
- traverse(FlatClassPath.RootPackage, subpackages, collection.mutable.Queue())
+ packages.put(ClassPath.RootPackage, PackageFileInfo(file, subpackages))
+ traverse(ClassPath.RootPackage, subpackages, collection.mutable.Queue())
packages
}
@@ -132,21 +133,21 @@ object ZipAndJarFlatClassPathFactory extends ZipAndJarFileLookupFactory {
(for (file <- pkg if file.isClass) yield ClassFileEntryImpl(file))(collection.breakOut)
}
- override private[nsc] def list(inPackage: String): FlatClassPathEntries = FlatClassPathEntries(packages(inPackage), classes(inPackage))
+ override private[nsc] def list(inPackage: String): ClassPathEntries = ClassPathEntries(packages(inPackage), classes(inPackage))
}
- private object ManifestResourcesFlatClassPath {
+ private object ManifestResourcesClassPath {
case class PackageFileInfo(packageFile: AbstractFile, subpackages: Seq[AbstractFile])
case class PackageInfo(packageName: String, subpackages: List[AbstractFile])
}
- override protected def createForZipFile(zipFile: AbstractFile): FlatClassPath =
+ override protected def createForZipFile(zipFile: AbstractFile): ClassPath =
if (zipFile.file == null) createWithoutUnderlyingFile(zipFile)
- else ZipArchiveFlatClassPath(zipFile.file)
+ else ZipArchiveClassPath(zipFile.file)
private def createWithoutUnderlyingFile(zipFile: AbstractFile) = zipFile match {
case manifestRes: ManifestResources =>
- ManifestResourcesFlatClassPath(manifestRes)
+ ManifestResourcesClassPath(manifestRes)
case _ =>
val errorMsg = s"Abstract files which don't have an underlying file and are not ManifestResources are not supported. There was $zipFile"
throw new IllegalArgumentException(errorMsg)
@@ -154,11 +155,11 @@ object ZipAndJarFlatClassPathFactory extends ZipAndJarFileLookupFactory {
}
/**
- * Manages creation of flat classpath for source files placed in zip and jar files.
+ * Manages creation of classpath for source files placed in zip and jar files.
* It should be the only way of creating them as it provides caching.
*/
-object ZipAndJarFlatSourcePathFactory extends ZipAndJarFileLookupFactory {
- private case class ZipArchiveFlatSourcePath(zipFile: File)
+object ZipAndJarSourcePathFactory extends ZipAndJarFileLookupFactory {
+ private case class ZipArchiveSourcePath(zipFile: File)
extends ZipArchiveFileLookup[SourceFileEntryImpl]
with NoClassPaths {
@@ -170,5 +171,5 @@ object ZipAndJarFlatSourcePathFactory extends ZipAndJarFileLookupFactory {
override protected def isRequiredFileType(file: AbstractFile): Boolean = file.isScalaOrJavaSource
}
- override protected def createForZipFile(zipFile: AbstractFile): FlatClassPath = ZipArchiveFlatSourcePath(zipFile.file)
+ override protected def createForZipFile(zipFile: AbstractFile): ClassPath = ZipArchiveSourcePath(zipFile.file)
}
diff --git a/src/compiler/scala/tools/nsc/classpath/ZipArchiveFileLookup.scala b/src/compiler/scala/tools/nsc/classpath/ZipArchiveFileLookup.scala
index a24d989306..9c147cf8cc 100644
--- a/src/compiler/scala/tools/nsc/classpath/ZipArchiveFileLookup.scala
+++ b/src/compiler/scala/tools/nsc/classpath/ZipArchiveFileLookup.scala
@@ -9,13 +9,14 @@ import scala.collection.Seq
import scala.reflect.io.AbstractFile
import scala.reflect.io.FileZipArchive
import FileUtils.AbstractFileOps
+import scala.tools.nsc.util.{ClassPath, ClassRepresentation}
/**
* A trait allowing to look for classpath entries of given type in zip and jar files.
* It provides common logic for classes handling class and source files.
* It's aware of things like e.g. META-INF directory which is correctly skipped.
*/
-trait ZipArchiveFileLookup[FileEntryType <: ClassRepClassPathEntry] extends FlatClassPath {
+trait ZipArchiveFileLookup[FileEntryType <: ClassRepresentation] extends ClassPath {
val zipFile: File
assert(zipFile != null, "Zip file in ZipArchiveFileLookup cannot be null")
@@ -39,7 +40,7 @@ trait ZipArchiveFileLookup[FileEntryType <: ClassRepClassPathEntry] extends Flat
entry <- dirEntry.iterator if isRequiredFileType(entry)
} yield createFileEntry(entry)
- override private[nsc] def list(inPackage: String): FlatClassPathEntries = {
+ override private[nsc] def list(inPackage: String): ClassPathEntries = {
val foundDirEntry = findDirEntry(inPackage)
foundDirEntry map { dirEntry =>
@@ -53,8 +54,8 @@ trait ZipArchiveFileLookup[FileEntryType <: ClassRepClassPathEntry] extends Flat
else if (isRequiredFileType(entry))
fileBuf += createFileEntry(entry)
}
- FlatClassPathEntries(pkgBuf, fileBuf)
- } getOrElse FlatClassPathEntries(Seq.empty, Seq.empty)
+ ClassPathEntries(pkgBuf, fileBuf)
+ } getOrElse ClassPathEntries(Seq.empty, Seq.empty)
}
private def findDirEntry(pkg: String): Option[archive.DirEntry] = {
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 7b98011759..9a0d86a94d 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -200,7 +200,6 @@ trait ScalaSettings extends AbsScalaSettings
val YmethodInfer = BooleanSetting ("-Yinfer-argument-types", "Infer types for arguments of overridden methods.")
val etaExpandKeepsStar = BooleanSetting ("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.").withDeprecationMessage(removalIn212)
val inferByName = BooleanSetting ("-Yinfer-by-name", "Allow inference of by-name types. This is a temporary option to ease transition. See SI-7899.").withDeprecationMessage(removalIn212)
- val YclasspathImpl = ChoiceSetting ("-YclasspathImpl", "implementation", "Choose classpath scanning method.", List(ClassPathRepresentationType.Recursive, ClassPathRepresentationType.Flat), ClassPathRepresentationType.Flat)
val YdisableFlatCpCaching = BooleanSetting ("-YdisableFlatCpCaching", "Do not cache flat classpath representation of classpath elements from jars across compiler instances.")
val exposeEmptyPackage = BooleanSetting ("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly()
@@ -389,8 +388,3 @@ trait ScalaSettings extends AbsScalaSettings
None
}
}
-
-object ClassPathRepresentationType {
- val Flat = "flat"
- val Recursive = "recursive"
-}
diff --git a/src/compiler/scala/tools/nsc/settings/Warnings.scala b/src/compiler/scala/tools/nsc/settings/Warnings.scala
index 79795bcc17..7ef606b6ef 100644
--- a/src/compiler/scala/tools/nsc/settings/Warnings.scala
+++ b/src/compiler/scala/tools/nsc/settings/Warnings.scala
@@ -25,6 +25,8 @@ trait Warnings {
// currently considered too noisy for general use
val warnUnusedImport = BooleanSetting("-Ywarn-unused-import", "Warn when imports are unused.")
+ val nowarnDefaultJunitMethods = BooleanSetting("-Ynowarn-default-junit-methods", "Don't warn when a JUnit @Test method is generated as a default method (not supported in JUnit 4).")
+
// Experimental lint warnings that are turned off, but which could be turned on programmatically.
// They are not activated by -Xlint and can't be enabled on the command line because they are not
// created using the standard factory methods.
@@ -57,6 +59,7 @@ trait Warnings {
val PackageObjectClasses = LintWarning("package-object-classes", "Class or object defined in package object.")
val UnsoundMatch = LintWarning("unsound-match", "Pattern match may not be typesafe.")
val StarsAlign = LintWarning("stars-align", "Pattern sequence wildcard must align with sequence component.")
+ val Constant = LintWarning("constant", "Evaluation of a constant arithmetic expression results in an error.")
def allLintWarnings = values.toSeq.asInstanceOf[Seq[LintWarning]]
}
@@ -78,6 +81,7 @@ trait Warnings {
def warnPackageObjectClasses = lint contains PackageObjectClasses
def warnUnsoundMatch = lint contains UnsoundMatch
def warnStarsAlign = lint contains StarsAlign
+ def warnConstant = lint contains Constant
// Lint warnings that are currently -Y, but deprecated in that usage
@deprecated("Use warnAdaptedArgs", since="2.11.2")
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
index 4f5589fd7c..b36d5d4ef1 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
@@ -10,10 +10,8 @@ import classfile.ClassfileParser
import java.io.IOException
import scala.reflect.internal.MissingRequirementError
import scala.reflect.internal.util.Statistics
-import scala.reflect.io.{ AbstractFile, NoAbstractFile }
-import scala.tools.nsc.classpath.FlatClassPath
-import scala.tools.nsc.settings.ClassPathRepresentationType
-import scala.tools.nsc.util.{ ClassPath, ClassRepresentation }
+import scala.reflect.io.{AbstractFile, NoAbstractFile}
+import scala.tools.nsc.util.{ClassPath, ClassRepresentation}
/** This class ...
*
@@ -154,7 +152,7 @@ abstract class SymbolLoaders {
/** Initialize toplevel class and module symbols in `owner` from class path representation `classRep`
*/
- def initializeFromClassPath(owner: Symbol, classRep: ClassRepresentation[AbstractFile]) {
+ def initializeFromClassPath(owner: Symbol, classRep: ClassRepresentation) {
((classRep.binary, classRep.source) : @unchecked) match {
case (Some(bin), Some(src))
if platform.needCompile(bin, src) && !binaryOnly(owner, classRep.name) =>
@@ -247,41 +245,11 @@ abstract class SymbolLoaders {
}
/**
- * Load contents of a package
- */
- class PackageLoader(classpath: ClassPath[AbstractFile]) extends SymbolLoader with FlagAgnosticCompleter {
- protected def description = s"package loader ${classpath.name}"
-
- protected def doComplete(root: Symbol) {
- assert(root.isPackageClass, root)
- // Time travel to a phase before refchecks avoids an initialization issue. `openPackageModule`
- // creates a module symbol and invokes invokes `companionModule` while the `infos` field is
- // still null. This calls `isModuleNotMethod`, which forces the `info` if run after refchecks.
- enteringPhase(phaseBeforeRefchecks) {
- root.setInfo(new PackageClassInfoType(newScope, root))
-
- if (!root.isRoot) {
- for (classRep <- classpath.classes) {
- initializeFromClassPath(root, classRep)
- }
- }
- if (!root.isEmptyPackageClass) {
- for (pkg <- classpath.packages) {
- enterPackage(root, pkg.name, new PackageLoader(pkg))
- }
-
- openPackageModule(root)
- }
- }
- }
- }
-
- /**
* Loads contents of a package
*/
- class PackageLoaderUsingFlatClassPath(packageName: String, classPath: FlatClassPath) extends SymbolLoader with FlagAgnosticCompleter {
+ class PackageLoader(packageName: String, classPath: ClassPath) extends SymbolLoader with FlagAgnosticCompleter {
protected def description = {
- val shownPackageName = if (packageName == FlatClassPath.RootPackage) "<root package>" else packageName
+ val shownPackageName = if (packageName == ClassPath.RootPackage) "<root package>" else packageName
s"package loader $shownPackageName"
}
@@ -298,9 +266,9 @@ abstract class SymbolLoaders {
val fullName = pkg.name
val name =
- if (packageName == FlatClassPath.RootPackage) fullName
+ if (packageName == ClassPath.RootPackage) fullName
else fullName.substring(packageName.length + 1)
- val packageLoader = new PackageLoaderUsingFlatClassPath(fullName, classPath)
+ val packageLoader = new PackageLoader(fullName, classPath)
enterPackage(root, name, packageLoader)
}
@@ -329,10 +297,7 @@ abstract class SymbolLoaders {
val loaders = SymbolLoaders.this.asInstanceOf[SymbolLoadersRefined]
- override def classFileLookup: util.ClassFileLookup[AbstractFile] = settings.YclasspathImpl.value match {
- case ClassPathRepresentationType.Recursive => platform.classPath
- case ClassPathRepresentationType.Flat => platform.flatClassPath
- }
+ override def classPath: ClassPath = platform.classPath
}
protected def description = "class file "+ classfile.toString
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index fffd48d145..0533d420cd 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -8,16 +8,16 @@ package tools.nsc
package symtab
package classfile
-import java.io.{ File, IOException }
+import java.io.{File, IOException}
import java.lang.Integer.toHexString
-import scala.collection.{ mutable, immutable }
-import scala.collection.mutable.{ ListBuffer, ArrayBuffer }
+import scala.collection.{immutable, mutable}
+import scala.collection.mutable.{ArrayBuffer, ListBuffer}
import scala.annotation.switch
-import scala.reflect.internal.{ JavaAccFlags }
-import scala.reflect.internal.pickling.{PickleBuffer, ByteCodecs}
+import scala.reflect.internal.JavaAccFlags
+import scala.reflect.internal.pickling.{ByteCodecs, PickleBuffer}
import scala.reflect.io.NoAbstractFile
+import scala.tools.nsc.util.ClassPath
import scala.tools.nsc.io.AbstractFile
-import scala.tools.nsc.util.ClassFileLookup
/** This abstract class implements a class file parser.
*
@@ -43,8 +43,8 @@ abstract class ClassfileParser {
*/
protected def lookupMemberAtTyperPhaseIfPossible(sym: Symbol, name: Name): Symbol
- /** The way of the class file lookup used by the compiler. */
- def classFileLookup: ClassFileLookup[AbstractFile]
+ /** The compiler classpath. */
+ def classPath: ClassPath
import definitions._
import scala.reflect.internal.ClassfileConstants._
@@ -357,7 +357,7 @@ abstract class ClassfileParser {
}
private def loadClassSymbol(name: Name): Symbol = {
- val file = classFileLookup findClassFile name.toString getOrElse {
+ val file = classPath findClassFile name.toString getOrElse {
// SI-5593 Scaladoc's current strategy is to visit all packages in search of user code that can be documented
// therefore, it will rummage through the classpath triggering errors whenever it encounters package objects
// that are not in their correct place (see bug for details)
@@ -1079,7 +1079,7 @@ abstract class ClassfileParser {
for (entry <- innerClasses.entries) {
// create a new class member for immediate inner classes
if (entry.outerName == currentClass) {
- val file = classFileLookup.findClassFile(entry.externalName.toString)
+ val file = classPath.findClassFile(entry.externalName.toString)
enterClassAndModule(entry, file.getOrElse(NoAbstractFile))
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index ac794201a4..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 {
@@ -1013,24 +1011,20 @@ abstract class Erasure extends AddInterfaces
// erasure the ScalaRunTime.hash overload goes from Unit => Int to BoxedUnit => Int.
// This must be because some earlier transformation is being skipped on ##, but so
// far I don't know what. For null we now define null.## == 0.
+ def staticsCall(methodName: TermName): Tree = {
+ val newTree = gen.mkMethodCall(RuntimeStaticsModule, methodName, qual :: Nil)
+ global.typer.typed(newTree)
+ }
+
qual.tpe.typeSymbol match {
case UnitClass | NullClass => LIT(0)
case IntClass => qual
case s @ (ShortClass | ByteClass | CharClass) => numericConversion(qual, s)
case BooleanClass => If(qual, LIT(true.##), LIT(false.##))
- case _ =>
- // Since we are past typer, we need to avoid creating trees carrying
- // overloaded types. This logic is custom (and technically incomplete,
- // although serviceable) for def hash. What is really needed is for
- // the overloading logic presently hidden away in a few different
- // places to be properly exposed so we can just call "resolveOverload"
- // after typer. Until then:
- val alts = ScalaRunTimeModule.info.member(nme.hash_).alternatives
- def alt1 = alts find (_.info.paramTypes.head =:= qual.tpe)
- def alt2 = ScalaRunTimeModule.info.member(nme.hash_) suchThat (_.info.paramTypes.head.typeSymbol == AnyClass)
- val newTree = gen.mkRuntimeCall(nme.hash_, qual :: Nil) setSymbol (alt1 getOrElse alt2)
-
- global.typer.typed(newTree)
+ case LongClass => staticsCall(nme.longHash)
+ case FloatClass => staticsCall(nme.floatHash)
+ case DoubleClass => staticsCall(nme.doubleHash)
+ case _ => staticsCall(nme.anyHash)
}
} else if (isPrimitiveValueClass(qual.tpe.typeSymbol)) {
// Rewrite 5.getClass to ScalaRunTime.anyValClass(5)
@@ -1147,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/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
index 8a0086dbdd..bc9f70679c 100644
--- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala
+++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
@@ -215,14 +215,16 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD
def mkSlowPathDef(clazz: Symbol, lzyVal: Symbol, cond: Tree, syncBody: List[Tree],
stats: List[Tree], retVal: Tree): Tree = {
- // Q: is there a reason to first set owner to `clazz` (by using clazz.newMethod), and then
- // changing it to lzyVal.owner very soon after? Could we just do lzyVal.owner.newMethod?
- val defSym = clazz.newMethod(nme.newLazyValSlowComputeName(lzyVal.name.toTermName), lzyVal.pos, STABLE | PRIVATE)
+ val owner = lzyVal.owner
+ val defSym = owner.newMethod(nme.newLazyValSlowComputeName(lzyVal.name.toTermName), lzyVal.pos, STABLE | PRIVATE)
defSym setInfo MethodType(List(), lzyVal.tpe.resultType)
- defSym.owner = lzyVal.owner
+ if (owner.isClass) owner.info.decls.enter(defSym)
debuglog(s"crete slow compute path $defSym with owner ${defSym.owner} for lazy val $lzyVal")
- if (bitmaps.contains(lzyVal))
- bitmaps(lzyVal).map(_.owner = defSym)
+ // this is a hack i don't understand for lazy vals nested in a lazy val, introduced in 3769f4d,
+ // tested in pos/t3670 (add9be64). class A { val n = { lazy val b = { lazy val dd = 3; dd }; b } }
+ // bitmaps has an entry bMethodSym -> List(bitmap$0), where bitmap$0.owner == bMethodSym.
+ // now we set bitmap$0.owner = b$lzycomputeMethodSym.
+ for (bitmap <- bitmaps(lzyVal)) bitmap.owner = defSym
val rhs: Tree = gen.mkSynchronizedCheck(clazz, cond, syncBody, stats).changeOwner(currentOwner -> defSym)
DefDef(defSym, addBitmapDefs(lzyVal, BLOCK(rhs, retVal)))
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index ed7ef0d8fd..19ba9345fa 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -8,6 +8,7 @@ package transform
import symtab._
import Flags._
+import scala.annotation.tailrec
import scala.collection.mutable
abstract class Mixin extends InfoTransform with ast.TreeDSL {
@@ -47,7 +48,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
sym.isMethod
&& (!sym.hasFlag(DEFERRED | SUPERACCESSOR) || (sym hasFlag lateDEFERRED))
&& sym.owner.isTrait
- && sym.isMethod
&& (!sym.isModule || sym.hasFlag(PRIVATE | LIFTED))
&& (!(sym hasFlag (ACCESSOR | SUPERACCESSOR)) || sym.isLazy)
&& !sym.isPrivate
@@ -240,8 +240,47 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
for (member <- mixinClass.info.decls ; if isImplementedStatically(member)) {
member overridingSymbol clazz match {
case NoSymbol =>
- if (clazz.info.findMember(member.name, 0, 0L, stableOnly = false).alternatives contains member)
- cloneAndAddMixinMember(mixinClass, member).asInstanceOf[TermSymbol] setAlias member
+ val isMemberOfClazz = clazz.info.findMember(member.name, 0, 0L, stableOnly = false).alternatives.contains(member)
+ if (isMemberOfClazz) {
+ // `member` is a concrete method defined in `mixinClass`, which is a base class of
+ // `clazz`, and the method is not overridden in `clazz`. A forwarder is needed if:
+ //
+ // - A non-trait base class of `clazz` defines a matching method. Example:
+ // class C {def f: Int}; trait T extends C {def f = 1}; class D extends T
+ // Even if C.f is abstract, the forwarder in D is needed, otherwise the JVM would
+ // resolve `D.f` to `C.f`, see jvms-6.5.invokevirtual.
+ //
+ // - There exists another concrete, matching method in a parent interface `p` of
+ // `clazz`, and the `mixinClass` does not itself extend `p`. In this case the
+ // forwarder is needed to disambiguate. Example:
+ // trait T1 {def f = 1}; trait T2 extends T1 {override def f = 2}; class C extends T2
+ // In C we don't need a forwarder for f because T2 extends T1, so the JVM resolves
+ // C.f to T2.f non-ambiguously. See jvms-5.4.3.3, "maximally-specific method".
+ // trait U1 {def f = 1}; trait U2 {self:U1 => override def f = 2}; class D extends U2
+ // In D the forwarder is needed, the interfaces U1 and U2 are unrelated at the JVM
+ // level.
+
+ @tailrec
+ def existsCompetingMethod(baseClasses: List[Symbol]): Boolean = baseClasses match {
+ case baseClass :: rest =>
+ if (baseClass ne mixinClass) {
+ val m = member.overriddenSymbol(baseClass)
+ val isCompeting = m.exists && {
+ !m.owner.isTraitOrInterface ||
+ (!m.isDeferred && !mixinClass.isNonBottomSubClass(m.owner))
+ }
+ isCompeting || existsCompetingMethod(rest)
+ } else existsCompetingMethod(rest)
+
+ case _ => false
+ }
+
+ if (existsCompetingMethod(clazz.baseClasses))
+ cloneAndAddMixinMember(mixinClass, member).asInstanceOf[TermSymbol] setAlias member
+ else if (!settings.nowarnDefaultJunitMethods && JUnitTestClass.exists && member.hasAnnotation(JUnitTestClass))
+ warning(member.pos, "JUnit tests in traits that are compiled as default methods are not executed by JUnit 4. JUnit 5 will fix this issue.")
+ }
+
case _ =>
}
}
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/ConstantFolder.scala b/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala
index 2f4771e9d4..2cd4785fbf 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala
@@ -40,9 +40,10 @@ abstract class ConstantFolder {
if ((x ne null) && x.tag != UnitTag) tree setType ConstantType(x)
else tree
} catch {
- case _: ArithmeticException => tree // the code will crash at runtime,
- // but that is better than the
- // compiler itself crashing
+ case e: ArithmeticException =>
+ if (settings.warnConstant)
+ warning(tree.pos, s"Evaluation of a constant expression results in an arithmetic error: ${e.getMessage}")
+ tree
}
private def foldUnop(op: Name, x: Constant): Constant = (op, x.tag) match {
@@ -102,13 +103,13 @@ abstract class ConstantFolder {
case nme.XOR => Constant(x.longValue ^ y.longValue)
case nme.AND => Constant(x.longValue & y.longValue)
case nme.LSL if x.tag <= IntTag
- => Constant(x.intValue << y.longValue)
+ => Constant(x.intValue << y.longValue.toInt) // TODO: remove .toInt once starr includes the fix for SI-9516 (2.12.0-M5)
case nme.LSL => Constant(x.longValue << y.longValue)
case nme.LSR if x.tag <= IntTag
- => Constant(x.intValue >>> y.longValue)
+ => Constant(x.intValue >>> y.longValue.toInt) // TODO: remove .toInt once starr includes the fix for SI-9516 (2.12.0-M5)
case nme.LSR => Constant(x.longValue >>> y.longValue)
case nme.ASR if x.tag <= IntTag
- => Constant(x.intValue >> y.longValue)
+ => Constant(x.intValue >> y.longValue.toInt) // TODO: remove .toInt once starr includes the fix for SI-9516 (2.12.0-M5)
case nme.ASR => Constant(x.longValue >> y.longValue)
case nme.EQ => Constant(x.longValue == y.longValue)
case nme.NE => Constant(x.longValue != y.longValue)
@@ -158,7 +159,7 @@ abstract class ConstantFolder {
else if (x.isNumeric && y.isNumeric) math.max(x.tag, y.tag)
else NoTag
- try optag match {
+ optag match {
case BooleanTag => foldBooleanOp(op, x, y)
case ByteTag | ShortTag | CharTag | IntTag => foldSubrangeOp(op, x, y)
case LongTag => foldLongOp(op, x, y)
@@ -167,8 +168,5 @@ abstract class ConstantFolder {
case StringTag if op == nme.ADD => Constant(x.stringValue + y.stringValue)
case _ => null
}
- catch {
- case _: ArithmeticException => null
- }
}
}
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/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index bcf9e018e2..d7c53ed3c4 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -12,7 +12,6 @@ import scala.reflect.internal.util.ListOfNil
import scala.reflect.macros.runtime.{AbortMacroException, MacroRuntimes}
import scala.reflect.macros.compiler.DefaultMacroCompiler
import scala.tools.reflect.FastTrack
-import scala.runtime.ScalaRunTime
import Fingerprint._
/**
@@ -239,7 +238,7 @@ trait Macros extends MacroRuntimes with Traces with Helpers {
if (!payload.contains(field)) failField("is supposed to be there")
val raw: Any = payload(field)
if (raw == null) failField(s"is not supposed to be null")
- val expected = ScalaRunTime.box(clazz)
+ val expected = box(clazz)
val actual = raw.getClass
if (!expected.isAssignableFrom(actual)) failField(s"has wrong type: expected $expected, actual $actual")
raw.asInstanceOf[T]
@@ -256,6 +255,19 @@ trait Macros extends MacroRuntimes with Traces with Helpers {
val signature = unpickle("signature", classOf[List[List[Fingerprint]]])
MacroImplBinding(isBundle, isBlackbox, className, methodName, signature, targs)
}
+
+ private def box[T](clazz: Class[T]): Class[_] = clazz match {
+ case java.lang.Byte.TYPE => classOf[java.lang.Byte]
+ case java.lang.Short.TYPE => classOf[java.lang.Short]
+ case java.lang.Character.TYPE => classOf[java.lang.Character]
+ case java.lang.Integer.TYPE => classOf[java.lang.Integer]
+ case java.lang.Long.TYPE => classOf[java.lang.Long]
+ case java.lang.Float.TYPE => classOf[java.lang.Float]
+ case java.lang.Double.TYPE => classOf[java.lang.Double]
+ case java.lang.Void.TYPE => classOf[scala.runtime.BoxedUnit]
+ case java.lang.Boolean.TYPE => classOf[java.lang.Boolean]
+ case _ => clazz
+ }
}
def bindMacroImpl(macroDef: Symbol, macroImplRef: Tree): Unit = {
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index 243a706745..6d883aee3d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -93,11 +93,14 @@ trait SyntheticMethods extends ast.TreeDSL {
def forwardToRuntime(method: Symbol): Tree =
forwardMethod(method, getMember(ScalaRunTimeModule, (method.name prepend "_")))(mkThis :: _)
- def callStaticsMethod(name: String)(args: Tree*): Tree = {
- val method = termMember(RuntimeStaticsModule, name)
+ def callStaticsMethodName(name: TermName)(args: Tree*): Tree = {
+ val method = RuntimeStaticsModule.info.member(name)
Apply(gen.mkAttributedRef(method), args.toList)
}
+ def callStaticsMethod(name: String)(args: Tree*): Tree =
+ callStaticsMethodName(newTermName(name))(args: _*)
+
// Any concrete member, including private
def hasConcreteImpl(name: Name) =
clazz.info.member(name).alternatives exists (m => !m.isDeferred)
@@ -245,10 +248,10 @@ trait SyntheticMethods extends ast.TreeDSL {
case BooleanClass => If(Ident(sym), Literal(Constant(1231)), Literal(Constant(1237)))
case IntClass => Ident(sym)
case ShortClass | ByteClass | CharClass => Select(Ident(sym), nme.toInt)
- case LongClass => callStaticsMethod("longHash")(Ident(sym))
- case DoubleClass => callStaticsMethod("doubleHash")(Ident(sym))
- case FloatClass => callStaticsMethod("floatHash")(Ident(sym))
- case _ => callStaticsMethod("anyHash")(Ident(sym))
+ case LongClass => callStaticsMethodName(nme.longHash)(Ident(sym))
+ case DoubleClass => callStaticsMethodName(nme.doubleHash)(Ident(sym))
+ case FloatClass => callStaticsMethodName(nme.floatHash)(Ident(sym))
+ case _ => callStaticsMethodName(nme.anyHash)(Ident(sym))
}
}
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/compiler/scala/tools/nsc/util/ClassFileLookup.scala b/src/compiler/scala/tools/nsc/util/ClassFileLookup.scala
deleted file mode 100644
index 5d8831a607..0000000000
--- a/src/compiler/scala/tools/nsc/util/ClassFileLookup.scala
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2014 Contributor. All rights reserved.
- */
-package scala.tools.nsc.util
-
-import scala.tools.nsc.Settings
-import scala.tools.nsc.classpath.{AggregateFlatClassPath, FlatClassPath, FlatClassPathFactory}
-import scala.tools.nsc.io.AbstractFile
-import java.net.URL
-
-/**
- * Simple interface that allows us to abstract over how class file lookup is performed
- * in different classpath representations.
- */
-// TODO at the end, after the possible removal of the old classpath representation, this class shouldn't be generic
-// T should be just changed to AbstractFile
-trait ClassFileLookup[T] {
- def findClassFile(name: String): Option[AbstractFile]
-
- /**
- * It returns both classes from class file and source files (as our base ClassRepresentation).
- * So note that it's not so strictly related to findClassFile.
- */
- def findClass(name: String): Option[ClassRepresentation[T]]
-
- /**
- * A sequence of URLs representing this classpath.
- */
- def asURLs: Seq[URL]
-
- /** The whole classpath in the form of one String.
- */
- def asClassPathString: String
-
- // for compatibility purposes
- @deprecated("Use asClassPathString instead of this one", "2.11.5")
- def asClasspathString: String = asClassPathString
-
- /** The whole sourcepath in the form of one String.
- */
- def asSourcePathString: String
-}
-
-object ClassFileLookup {
- def createForFile(f: AbstractFile, current: ClassFileLookup[AbstractFile], settings: Settings): ClassFileLookup[AbstractFile] = current match {
- case cp: ClassPath[_] => cp.context.newClassPath(f)
- case _: FlatClassPath => FlatClassPathFactory.newClassPath(f, settings)
- }
-
- def createAggregate(elems: Iterable[ClassFileLookup[AbstractFile]], current: ClassFileLookup[AbstractFile]): ClassFileLookup[AbstractFile] = {
- assert(elems.nonEmpty)
- if (elems.size == 1) elems.head
- else current match {
- case cp: ClassPath[_] =>
- new MergedClassPath(elems.asInstanceOf[Iterable[ClassPath[AbstractFile]]], cp.context)
-
- case _: FlatClassPath =>
- AggregateFlatClassPath.createAggregate(elems.asInstanceOf[Iterable[FlatClassPath]].toSeq : _*)
- }
- }
-}
-
-/**
- * Represents classes which can be loaded with a ClassfileLoader and/or SourcefileLoader.
- */
-// TODO at the end, after the possible removal of the old classpath implementation, this class shouldn't be generic
-// T should be just changed to AbstractFile
-trait ClassRepresentation[T] {
- def binary: Option[T]
- def source: Option[AbstractFile]
-
- def name: String
-}
-
-object ClassRepresentation {
- def unapply[T](classRep: ClassRepresentation[T]): Option[(Option[T], Option[AbstractFile])] =
- Some((classRep.binary, classRep.source))
-}
diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala
index 6cdc3856cd..cef2fc4bbf 100644
--- a/src/compiler/scala/tools/nsc/util/ClassPath.scala
+++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala
@@ -7,28 +7,61 @@
package scala.tools.nsc
package util
-import io.{ AbstractFile, Directory, File, Jar }
+import io.{AbstractFile, Directory, File, Jar}
import java.net.MalformedURLException
import java.net.URL
import java.util.regex.PatternSyntaxException
-import scala.collection.{ mutable, immutable }
-import scala.reflect.internal.util.StringOps.splitWhere
-import scala.tools.nsc.classpath.FileUtils
import File.pathSeparator
-import FileUtils.endsClass
-import FileUtils.endsScalaOrJava
import Jar.isJarOrZip
-/** <p>
- * This module provides star expansion of '-classpath' option arguments, behaves the same as
- * java, see [[http://docs.oracle.com/javase/6/docs/technotes/tools/windows/classpath.html]]
- * </p>
- *
- * @author Stepan Koltsov
- */
+/**
+ * A representation of the compiler's class- or sourcepath.
+ */
+trait ClassPath {
+ import scala.tools.nsc.classpath._
+ def asURLs: Seq[URL]
+
+ /** Empty string represents root package */
+ private[nsc] def packages(inPackage: String): Seq[PackageEntry]
+ private[nsc] def classes(inPackage: String): Seq[ClassFileEntry]
+ private[nsc] def sources(inPackage: String): Seq[SourceFileEntry]
+
+ /** Allows to get entries for packages and classes merged with sources possibly in one pass. */
+ private[nsc] def list(inPackage: String): ClassPathEntries
+
+ /**
+ * It returns both classes from class file and source files (as our base ClassRepresentation).
+ * So note that it's not so strictly related to findClassFile.
+ */
+ def findClass(className: String): Option[ClassRepresentation] = {
+ // A default implementation which should be overridden, if we can create the more efficient
+ // solution for a given type of ClassPath
+ val (pkg, simpleClassName) = PackageNameUtils.separatePkgAndClassNames(className)
+
+ val foundClassFromClassFiles = classes(pkg).find(_.name == simpleClassName)
+ def findClassInSources = sources(pkg).find(_.name == simpleClassName)
+
+ foundClassFromClassFiles orElse findClassInSources
+ }
+ def findClassFile(className: String): Option[AbstractFile]
+
+ def asClassPathStrings: Seq[String]
+
+ /** The whole classpath in the form of one String.
+ */
+ def asClassPathString: String = ClassPath.join(asClassPathStrings: _*)
+ // for compatibility purposes
+ @deprecated("Use asClassPathString instead of this one", "2.11.5")
+ def asClasspathString: String = asClassPathString
+
+ /** The whole sourcepath in the form of one String.
+ */
+ def asSourcePathString: String
+}
+
object ClassPath {
- import scala.language.postfixOps
+ val RootPackage = ""
/** Expand single path entry */
private def expandS(pattern: String): List[String] = {
@@ -36,14 +69,14 @@ object ClassPath {
/* Get all subdirectories, jars, zips out of a directory. */
def lsDir(dir: Directory, filt: String => Boolean = _ => true) =
- dir.list filter (x => filt(x.name) && (x.isDirectory || isJarOrZip(x))) map (_.path) toList
+ dir.list.filter(x => filt(x.name) && (x.isDirectory || isJarOrZip(x))).map(_.path).toList
if (pattern == "*") lsDir(Directory("."))
else if (pattern endsWith wildSuffix) lsDir(Directory(pattern dropRight 2))
else if (pattern contains '*') {
try {
val regexp = ("^" + pattern.replaceAllLiterally("""\*""", """.*""") + "$").r
- lsDir(Directory(pattern).parent, regexp findFirstIn _ isDefined)
+ lsDir(Directory(pattern).parent, regexp.findFirstIn(_).isDefined)
}
catch { case _: PatternSyntaxException => List(pattern) }
}
@@ -51,7 +84,7 @@ object ClassPath {
}
/** Split classpath using platform-dependent path separator */
- def split(path: String): List[String] = (path split pathSeparator).toList filterNot (_ == "") distinct
+ def split(path: String): List[String] = (path split pathSeparator).toList.filterNot(_ == "").distinct
/** Join classpath using platform-dependent path separator */
def join(paths: String*): String = paths filterNot (_ == "") mkString pathSeparator
@@ -68,9 +101,10 @@ object ClassPath {
def expandDir(extdir: String): List[String] = {
AbstractFile getDirectory extdir match {
case null => Nil
- case dir => dir filter (_.isClassContainer) map (x => new java.io.File(dir.file, x.name) getPath) toList
+ case dir => dir.filter(_.isClassContainer).map(x => new java.io.File(dir.file, x.name).getPath).toList
}
}
+
/** Expand manifest jar classpath entries: these are either urls, or paths
* relative to the location of the jar.
*/
@@ -88,302 +122,30 @@ object ClassPath {
try Some(new URL(spec))
catch { case _: MalformedURLException => None }
- /** A class modeling aspects of a ClassPath which should be
- * propagated to any classpaths it creates.
- */
- abstract class ClassPathContext[T] extends classpath.ClassPathFactory[ClassPath[T]] {
- /** A filter which can be used to exclude entities from the classpath
- * based on their name.
- */
- def isValidName(name: String): Boolean = true
-
- /** Filters for assessing validity of various entities.
- */
- def validClassFile(name: String) = endsClass(name) && isValidName(name)
- def validPackage(name: String) = (name != "META-INF") && (name != "") && (name.charAt(0) != '.')
- def validSourceFile(name: String) = endsScalaOrJava(name)
-
- /** From the representation to its identifier.
- */
- def toBinaryName(rep: T): String
-
- def sourcesInPath(path: String): List[ClassPath[T]] =
- for (file <- expandPath(path, expandStar = false) ; dir <- Option(AbstractFile getDirectory file)) yield
- new SourcePath[T](dir, this)
- }
-
def manifests: List[java.net.URL] = {
- import scala.collection.convert.WrapAsScala.enumerationAsScalaIterator
- Thread.currentThread().getContextClassLoader()
- .getResources("META-INF/MANIFEST.MF")
- .filter(_.getProtocol == "jar").toList
+ import scala.collection.JavaConverters._
+ val resources = Thread.currentThread().getContextClassLoader().getResources("META-INF/MANIFEST.MF")
+ resources.asScala.filter(_.getProtocol == "jar").toList
}
- class JavaContext extends ClassPathContext[AbstractFile] {
- def toBinaryName(rep: AbstractFile) = {
- val name = rep.name
- assert(endsClass(name), name)
- FileUtils.stripClassExtension(name)
- }
+ @deprecated("Shim for sbt's compiler interface", since = "2.12")
+ sealed abstract class ClassPathContext
- def newClassPath(dir: AbstractFile) = new DirectoryClassPath(dir, this)
- }
-
- object DefaultJavaContext extends JavaContext
-
- /** From the source file to its identifier.
- */
- def toSourceName(f: AbstractFile): String = FileUtils.stripSourceExtension(f.name)
+ @deprecated("Shim for sbt's compiler interface", since = "2.12")
+ sealed abstract class JavaContext
}
-import ClassPath._
-
-/**
- * Represents a package which contains classes and other packages
- */
-abstract class ClassPath[T] extends ClassFileLookup[T] {
- /**
- * The short name of the package (without prefix)
- */
+trait ClassRepresentation {
def name: String
-
- /**
- * A String representing the origin of this classpath element, if known.
- * For example, the path of the directory or jar.
- */
- def origin: Option[String] = None
-
- /** Info which should be propagated to any sub-classpaths.
- */
- def context: ClassPathContext[T]
-
- /** Lists of entities.
- */
- def classes: IndexedSeq[ClassRepresentation[T]]
- def packages: IndexedSeq[ClassPath[T]]
- def sourcepaths: IndexedSeq[AbstractFile]
-
- /** The entries this classpath is composed of. In class `ClassPath` it's just the singleton list containing `this`.
- * Subclasses such as `MergedClassPath` typically return lists with more elements.
- */
- def entries: IndexedSeq[ClassPath[T]] = IndexedSeq(this)
-
- /** Merge classpath of `platform` and `urls` into merged classpath */
- def mergeUrlsIntoClassPath(urls: URL*): MergedClassPath[T] = {
- // Collect our new jars/directories and add them to the existing set of classpaths
- val allEntries =
- (entries ++
- urls.map(url => context.newClassPath(io.AbstractFile.getURL(url)))
- ).distinct
-
- // Combine all of our classpaths (old and new) into one merged classpath
- new MergedClassPath(allEntries, context)
- }
-
- /**
- * Represents classes which can be loaded with a ClassfileLoader and/or SourcefileLoader.
- */
- case class ClassRep(binary: Option[T], source: Option[AbstractFile]) extends ClassRepresentation[T] {
- def name: String = binary match {
- case Some(x) => context.toBinaryName(x)
- case _ =>
- assert(source.isDefined)
- toSourceName(source.get)
- }
- }
-
- /** Filters for assessing validity of various entities.
- */
- def validClassFile(name: String) = context.validClassFile(name)
- def validPackage(name: String) = context.validPackage(name)
- def validSourceFile(name: String) = context.validSourceFile(name)
-
- /**
- * Find a ClassRep given a class name of the form "package.subpackage.ClassName".
- * Does not support nested classes on .NET
- */
- override def findClass(name: String): Option[ClassRepresentation[T]] =
- splitWhere(name, _ == '.', doDropIndex = true) match {
- case Some((pkg, rest)) =>
- val rep = packages find (_.name == pkg) flatMap (_ findClass rest)
- rep map {
- case x: ClassRepresentation[T] => x
- case x => throw new FatalError("Unexpected ClassRep '%s' found searching for name '%s'".format(x, name))
- }
- case _ =>
- classes find (_.name == name)
- }
-
- override def findClassFile(name: String): Option[AbstractFile] =
- findClass(name) match {
- case Some(ClassRepresentation(Some(x: AbstractFile), _)) => Some(x)
- case _ => None
- }
-
- override def asSourcePathString: String = sourcepaths.mkString(pathSeparator)
-
- def sortString = join(split(asClassPathString).sorted: _*)
- override def equals(that: Any) = that match {
- case x: ClassPath[_] => this.sortString == x.sortString
- case _ => false
- }
- override def hashCode = sortString.hashCode()
-}
-
-/**
- * A Classpath containing source files
- */
-class SourcePath[T](dir: AbstractFile, val context: ClassPathContext[T]) extends ClassPath[T] {
- import FileUtils.AbstractFileOps
-
- def name = dir.name
- override def origin = dir.underlyingSource map (_.path)
- def asURLs = dir.toURLs()
- def asClassPathString = dir.path
- val sourcepaths: IndexedSeq[AbstractFile] = IndexedSeq(dir)
-
- private def traverse() = {
- val classBuf = immutable.Vector.newBuilder[ClassRep]
- val packageBuf = immutable.Vector.newBuilder[SourcePath[T]]
- dir foreach { f =>
- if (!f.isDirectory && validSourceFile(f.name))
- classBuf += ClassRep(None, Some(f))
- else if (f.isDirectory && validPackage(f.name))
- packageBuf += new SourcePath[T](f, context)
- }
- (packageBuf.result(), classBuf.result())
- }
-
- lazy val (packages, classes) = traverse()
- override def toString() = "sourcepath: "+ dir.toString()
+ def binary: Option[AbstractFile]
+ def source: Option[AbstractFile]
}
-/**
- * A directory (or a .jar file) containing classfiles and packages
- */
-class DirectoryClassPath(val dir: AbstractFile, val context: ClassPathContext[AbstractFile]) extends ClassPath[AbstractFile] {
- import FileUtils.AbstractFileOps
-
- def name = dir.name
- override def origin = dir.underlyingSource map (_.path)
- def asURLs = dir.toURLs(default = Seq(new URL(name)))
- def asClassPathString = dir.path
- val sourcepaths: IndexedSeq[AbstractFile] = IndexedSeq()
-
- // calculates (packages, classes) in one traversal.
- private def traverse() = {
- val classBuf = immutable.Vector.newBuilder[ClassRep]
- val packageBuf = immutable.Vector.newBuilder[DirectoryClassPath]
- dir foreach {
- f =>
- // Optimization: We assume the file was not changed since `dir` called
- // `Path.apply` and categorized existent files as `Directory`
- // or `File` (avoids IO operation JFile.isDirectory()).
- val isDirectory = f match {
- case pf: io.PlainFile => pf.givenPath match {
- case _: io.Directory => true
- case _: io.File => false
- case _ => f.isDirectory
- }
- case _ =>
- f.isDirectory
- }
- if (!isDirectory && validClassFile(f.name))
- classBuf += ClassRep(Some(f), None)
- else if (isDirectory && validPackage(f.name))
- packageBuf += new DirectoryClassPath(f, context)
- }
- (packageBuf.result(), classBuf.result())
- }
+@deprecated("Shim for sbt's compiler interface", since = "2.12")
+sealed abstract class DirectoryClassPath
- lazy val (packages, classes) = traverse()
- override def toString() = "directory classpath: "+ origin.getOrElse("?")
-}
+@deprecated("Shim for sbt's compiler interface", since = "2.12")
+sealed abstract class MergedClassPath
-/**
- * A classpath unifying multiple class- and sourcepath entries.
- */
-class MergedClassPath[T](
- override val entries: IndexedSeq[ClassPath[T]],
- val context: ClassPathContext[T])
-extends ClassPath[T] {
-
- def this(entries: TraversableOnce[ClassPath[T]], context: ClassPathContext[T]) =
- this(entries.toIndexedSeq, context)
-
- def name = entries.head.name
- def asURLs = (entries flatMap (_.asURLs)).toList
- lazy val sourcepaths: IndexedSeq[AbstractFile] = entries flatMap (_.sourcepaths)
-
- override def origin = Some(entries map (x => x.origin getOrElse x.name) mkString ("Merged(", ", ", ")"))
- override def asClassPathString: String = join(entries map (_.asClassPathString) : _*)
-
- lazy val classes: IndexedSeq[ClassRepresentation[T]] = {
- var count = 0
- val indices = mutable.HashMap[String, Int]()
- val cls = new mutable.ArrayBuffer[ClassRepresentation[T]](1024)
-
- for (e <- entries; c <- e.classes) {
- val name = c.name
- if (indices contains name) {
- val idx = indices(name)
- val existing = cls(idx)
-
- if (existing.binary.isEmpty && c.binary.isDefined)
- cls(idx) = ClassRep(binary = c.binary, source = existing.source)
- if (existing.source.isEmpty && c.source.isDefined)
- cls(idx) = ClassRep(binary = existing.binary, source = c.source)
- }
- else {
- indices(name) = count
- cls += c
- count += 1
- }
- }
- cls.toIndexedSeq
- }
-
- lazy val packages: IndexedSeq[ClassPath[T]] = {
- var count = 0
- val indices = mutable.HashMap[String, Int]()
- val pkg = new mutable.ArrayBuffer[ClassPath[T]](256)
-
- for (e <- entries; p <- e.packages) {
- val name = p.name
- if (indices contains name) {
- val idx = indices(name)
- pkg(idx) = addPackage(pkg(idx), p)
- }
- else {
- indices(name) = count
- pkg += p
- count += 1
- }
- }
- pkg.toIndexedSeq
- }
-
- private def addPackage(to: ClassPath[T], pkg: ClassPath[T]) = {
- val newEntries: IndexedSeq[ClassPath[T]] = to match {
- case cp: MergedClassPath[_] => cp.entries :+ pkg
- case _ => IndexedSeq(to, pkg)
- }
- new MergedClassPath[T](newEntries, context)
- }
-
- def show() {
- println("ClassPath %s has %d entries and results in:\n".format(name, entries.size))
- asClassPathString split ':' foreach (x => println(" " + x))
- }
-
- override def toString() = "merged classpath "+ entries.mkString("(", "\n", ")")
-}
-
-/**
- * The classpath when compiling with target:jvm. Binary files (classfiles) are represented
- * as AbstractFile. nsc.io.ZipArchive is used to view zip/jar archives as directories.
- */
-class JavaClassPath(
- containers: IndexedSeq[ClassPath[AbstractFile]],
- context: JavaContext)
-extends MergedClassPath[AbstractFile](containers, context) { }
+@deprecated("Shim for sbt's compiler interface", since = "2.12")
+sealed abstract class JavaClassPath
diff --git a/src/compiler/scala/tools/reflect/ReflectMain.scala b/src/compiler/scala/tools/reflect/ReflectMain.scala
index 8d8418945a..7d82910699 100644
--- a/src/compiler/scala/tools/reflect/ReflectMain.scala
+++ b/src/compiler/scala/tools/reflect/ReflectMain.scala
@@ -5,12 +5,12 @@ import scala.reflect.internal.util.ScalaClassLoader
import scala.tools.nsc.Driver
import scala.tools.nsc.Global
import scala.tools.nsc.Settings
-import scala.tools.util.PathResolverFactory
+import scala.tools.util.PathResolver
object ReflectMain extends Driver {
private def classloaderFromSettings(settings: Settings) = {
- val classPathURLs = PathResolverFactory.create(settings).resultAsURLs
+ val classPathURLs = new PathResolver(settings).resultAsURLs
ScalaClassLoader.fromURLs(classPathURLs, getClass.getClassLoader)
}
diff --git a/src/compiler/scala/tools/util/PathResolver.scala b/src/compiler/scala/tools/util/PathResolver.scala
index 9decc99c8d..c351b6ace1 100644
--- a/src/compiler/scala/tools/util/PathResolver.scala
+++ b/src/compiler/scala/tools/util/PathResolver.scala
@@ -10,12 +10,10 @@ package util
import java.net.URL
import scala.tools.reflect.WrappedProperties.AccessControl
import scala.tools.nsc.Settings
-import scala.tools.nsc.util.{ ClassFileLookup, ClassPath, JavaClassPath }
-import scala.reflect.io.{ File, Directory, Path, AbstractFile }
-import ClassPath.{ JavaContext, DefaultJavaContext, split }
+import scala.tools.nsc.util.ClassPath
+import scala.reflect.io.{Directory, File, Path}
import PartialFunction.condOpt
-import scala.tools.nsc.classpath.{ AggregateFlatClassPath, ClassPathFactory, FlatClassPath, FlatClassPathFactory }
-import scala.tools.nsc.settings.ClassPathRepresentationType
+import scala.tools.nsc.classpath._
// Loosely based on the draft specification at:
// https://wiki.scala-lang.org/display/SIW/Classpath
@@ -40,7 +38,7 @@ object PathResolver {
}
/** pretty print class path */
- def ppcp(s: String) = split(s) match {
+ def ppcp(s: String) = ClassPath.split(s) match {
case Nil => ""
case Seq(x) => x
case xs => xs.mkString(EOL, EOL, "")
@@ -164,13 +162,6 @@ object PathResolver {
|}""".asLines
}
- @deprecated("This method is no longer used be scalap and will be deleted", "2.11.5")
- def fromPathString(path: String, context: JavaContext = DefaultJavaContext): JavaClassPath = {
- val s = new Settings()
- s.classpath.value = path
- new PathResolver(s, context).result
- }
-
/** With no arguments, show the interesting values in Environment and Defaults.
* If there are arguments, show those in Calculated as if those options had been
* given to a scala runner.
@@ -182,28 +173,19 @@ object PathResolver {
} else {
val settings = new Settings()
val rest = settings.processArguments(args.toList, processAll = false)._2
- val pr = PathResolverFactory.create(settings)
+ val pr = new PathResolver(settings)
println("COMMAND: 'scala %s'".format(args.mkString(" ")))
println("RESIDUAL: 'scala %s'\n".format(rest.mkString(" ")))
pr.result match {
- case cp: JavaClassPath =>
- cp.show()
- case cp: AggregateFlatClassPath =>
+ case cp: AggregateClassPath =>
println(s"ClassPath has ${cp.aggregates.size} entries and results in:\n${cp.asClassPathStrings}")
}
}
}
-trait PathResolverResult {
- def result: ClassFileLookup[AbstractFile]
-
- def resultAsURLs: Seq[URL] = result.asURLs
-}
-
-abstract class PathResolverBase[BaseClassPathType <: ClassFileLookup[AbstractFile], ResultClassPathType <: BaseClassPathType]
-(settings: Settings, classPathFactory: ClassPathFactory[BaseClassPathType])
- extends PathResolverResult {
+final class PathResolver(settings: Settings) {
+ private val classPathFactory = new ClassPathFactory(settings)
import PathResolver.{ AsLines, Defaults, ppcp }
@@ -251,7 +233,7 @@ abstract class PathResolverBase[BaseClassPathType <: ClassFileLookup[AbstractFil
import classPathFactory._
// Assemble the elements!
- def basis = List[Traversable[BaseClassPathType]](
+ def basis = List[Traversable[ClassPath]](
classesInPath(javaBootClassPath), // 1. The Java bootstrap class path.
contentsOfDirsInPath(javaExtDirs), // 2. The Java extension class path.
classesInExpandedPath(javaUserClassPath), // 3. The Java application class path.
@@ -282,7 +264,7 @@ abstract class PathResolverBase[BaseClassPathType <: ClassFileLookup[AbstractFil
import PathResolver.MkLines
- def result: ResultClassPathType = {
+ def result: ClassPath = {
val cp = computeResult()
if (settings.Ylogcp) {
Console print f"Classpath built from ${settings.toConciseString} %n"
@@ -295,34 +277,11 @@ abstract class PathResolverBase[BaseClassPathType <: ClassFileLookup[AbstractFil
cp
}
+ def resultAsURLs: Seq[URL] = result.asURLs
+
@deprecated("Use resultAsURLs instead of this one", "2.11.5")
def asURLs: List[URL] = resultAsURLs.toList
- protected def computeResult(): ResultClassPathType
+ private def computeResult(): ClassPath = AggregateClassPath(containers.toIndexedSeq)
}
-class PathResolver(settings: Settings, context: JavaContext)
- extends PathResolverBase[ClassPath[AbstractFile], JavaClassPath](settings, context) {
-
- def this(settings: Settings) = this(settings, DefaultJavaContext)
-
- override protected def computeResult(): JavaClassPath =
- new JavaClassPath(containers.toIndexedSeq, context)
-}
-
-class FlatClassPathResolver(settings: Settings, flatClassPathFactory: ClassPathFactory[FlatClassPath])
- extends PathResolverBase[FlatClassPath, AggregateFlatClassPath](settings, flatClassPathFactory) {
-
- def this(settings: Settings) = this(settings, new FlatClassPathFactory(settings))
-
- override protected def computeResult(): AggregateFlatClassPath = AggregateFlatClassPath(containers.toIndexedSeq)
-}
-
-object PathResolverFactory {
-
- def create(settings: Settings): PathResolverResult =
- settings.YclasspathImpl.value match {
- case ClassPathRepresentationType.Flat => new FlatClassPathResolver(settings)
- case ClassPathRepresentationType.Recursive => new PathResolver(settings)
- }
-}
diff --git a/src/eclipse/README.md b/src/eclipse/README.md
index 3df7fbed7d..f67fa26e5e 100644
--- a/src/eclipse/README.md
+++ b/src/eclipse/README.md
@@ -7,21 +7,20 @@ The following points describe how to build Scala using Eclipse.
0. Download the [Scala IDE bundle](http://scala-ide.org/download/sdk.html). It comes preconfigured for optimal performance.
-0. Run `ant init` to download some necessary jars.
-
-0. Import the project (in `src/eclipse`) via `File` → `Import Existing Projects` and navigate to `scala/src/eclipse`. Check all projects and click ok.
-
-0. You need to define a `path variable` inside Eclipse. Define `SCALA_BASEDIR` in
-`Preferences/General/Workspace/Linked Resources`. The value should be the absolute
-path to your Scala checkout. All paths in the project files are relative to this one,
-so nothing will work before you do so.
-
- The same `SCALA_BASEDIR` variable needs to be defined as a `classpath variable` in
+0. Run `ant build` to download some necessary jars and see a successful build.
+
+0. You need to define a `path variable` and a `classpath variable` inside Eclipse, both pointing to the Scala checkout directory:
+ - (experimental): run `./update-workspace.sh scala_checkout_dir [workspace_dir]`. This should update your workspace settings
+ (restart Eclipse if it was running). For example:
+ ```
+ ./update-workspace.sh $HOME/git/scala ~/Documents/workspace-scalac
+ ```
+ - If the above didn't work, you can perform these steps manually: Define `SCALA_BASEDIR` in `Preferences/General/Workspace/Linked Resources`. The value should be the absolute
+path to your Scala checkout. All paths in the project files are relative to this one, so nothing will work before you do so.
+The same `SCALA_BASEDIR` variable needs to be defined **also** as a `classpath variable` in
`Java/Build Path/Classpath Variables`.
- Additionally, we start using Maven dependencies (e.g. `JUnit`) so you need to define another
-`classpath variable` inside Eclipse. Define `M2_REPO` in `Java/Build Path/Classpath Variables`
-to point to your local Maven repository (e.g. `$HOME/.m2/repository`).
+0. Import the project (in `src/eclipse`) via `File` → `Import Existing Projects` and navigate to `scala/src/eclipse`. Check all projects and click ok.
Lastly, the JRE used by Eclipse needs to know the path to the `JLine` library, which is used by the REPL.
To set the JAR file, navigate to `Java/Installed JREs`, select the default JRE, press `Edit/Add External JARs...`
diff --git a/src/eclipse/interactive/.classpath b/src/eclipse/interactive/.classpath
index 929ce65f2a..721351a207 100644
--- a/src/eclipse/interactive/.classpath
+++ b/src/eclipse/interactive/.classpath
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="interactive"/>
+ <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/asm/scala-asm-5.0.4-scala-3.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/scaladoc"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/scala-compiler"/>
<classpathentry combineaccessrules="false" kind="src" path="/scala-library"/>
- <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/asm/scala-asm-5.0.4-scala-3.jar"/>
<classpathentry kind="output" path="build-quick-interactive"/>
</classpath>
diff --git a/src/eclipse/partest/.classpath b/src/eclipse/partest/.classpath
index 63f46f46cd..22afd65d43 100644
--- a/src/eclipse/partest/.classpath
+++ b/src/eclipse/partest/.classpath
@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="partest-extras"/>
+ <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/asm/scala-asm-5.0.4-scala-3.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/repl"/>
- <classpathentry kind="var" path="M2_REPO/com/googlecode/java-diff-utils/diffutils/1.3.0/diffutils-1.3.0.jar"/>
- <classpathentry kind="var" path="M2_REPO/org/scala-sbt/test-interface/1.0/test-interface-1.0.jar"/>
- <classpathentry kind="var" path="M2_REPO/org/scala-lang/modules/scala-partest_2.12.0-M2/1.0.9/scala-partest_2.12.0-M2-1.0.9.jar"/>
+ <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/partest/diffutils-1.3.0.jar"/>
+ <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/partest/test-interface-1.0.jar"/>
<classpathentry kind="var" path="SCALA_BASEDIR/lib/ant/ant.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/scala-compiler"/>
<classpathentry combineaccessrules="false" kind="src" path="/scala-library"/>
- <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/asm/scala-asm-5.0.4-scala-3.jar"/>
+ <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/partest/scala-partest_2.12.0-M4-1.0.14.jar"/>
<classpathentry kind="output" path="build-quick-partest-extras"/>
</classpath>
diff --git a/src/eclipse/reflect/.classpath b/src/eclipse/reflect/.classpath
index 3f14621da7..ee6bcd47da 100644
--- a/src/eclipse/reflect/.classpath
+++ b/src/eclipse/reflect/.classpath
@@ -3,5 +3,6 @@
<classpathentry kind="src" path="reflect"/>
<classpathentry combineaccessrules="false" kind="src" path="/scala-library"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.scala-ide.sdt.launching.SCALA_CONTAINER"/>
<classpathentry kind="output" path="build-quick-reflect"/>
</classpath>
diff --git a/src/eclipse/repl/.classpath b/src/eclipse/repl/.classpath
index 085b58f668..682377adc9 100644
--- a/src/eclipse/repl/.classpath
+++ b/src/eclipse/repl/.classpath
@@ -1,10 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="repl"/>
- <classpathentry kind="var" path="M2_REPO/jline/jline/2.12.1/jline-2.12.1.jar"/>
+ <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/asm/scala-asm-5.0.4-scala-3.jar"/>
+ <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/repl/jline-2.12.1.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/scala-compiler"/>
<classpathentry combineaccessrules="false" kind="src" path="/scala-library"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
- <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/asm/scala-asm-5.0.4-scala-3.jar"/>
+ <classpathentry kind="con" path="org.scala-ide.sdt.launching.SCALA_CONTAINER"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/interactive"/>
<classpathentry kind="output" path="build-quick-repl"/>
</classpath>
diff --git a/src/eclipse/scala-compiler/.classpath b/src/eclipse/scala-compiler/.classpath
index bbed3324c4..625b9b2e4b 100644
--- a/src/eclipse/scala-compiler/.classpath
+++ b/src/eclipse/scala-compiler/.classpath
@@ -4,7 +4,8 @@
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/reflect"/>
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/scala-library"/>
<classpathentry kind="var" path="SCALA_BASEDIR/lib/ant/ant.jar"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="var" path="SCALA_BASEDIR/build/deps/asm/scala-asm-5.0.4-scala-3.jar"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.scala-ide.sdt.launching.SCALA_CONTAINER"/>
<classpathentry kind="output" path="build-quick-compiler"/>
</classpath>
diff --git a/src/eclipse/scaladoc/.classpath b/src/eclipse/scaladoc/.classpath
index 3a3ebf7799..b4450df4ef 100644
--- a/src/eclipse/scaladoc/.classpath
+++ b/src/eclipse/scaladoc/.classpath
@@ -2,13 +2,12 @@
<classpath>
<classpathentry kind="src" path="scaladoc"/>
<classpathentry kind="var" path="SCALA_BASEDIR/lib/ant/ant.jar"/>
+ <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/asm/scala-asm-5.0.4-scala-3.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/scala-compiler"/>
<classpathentry combineaccessrules="false" kind="src" path="/scala-library"/>
- <classpathentry combineaccessrules="false" kind="src" path="/partest-extras"/>
- <classpathentry kind="var" path="M2_REPO/org/scala-lang/modules/scala-xml_2.12.0-M2/1.0.5/scala-xml_2.12.0-M2-1.0.5.jar"/>
- <classpathentry kind="var" path="M2_REPO/org/scala-lang/modules/scala-parser-combinators_2.12.0-M2/1.0.4/scala-parser-combinators_2.12.0-M2-1.0.4.jar"/>
- <classpathentry kind="var" path="M2_REPO/org/scala-lang/modules/scala-partest_2.12.0-M2/1.0.9/scala-partest_2.12.0-M2-1.0.9.jar"/>
- <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/asm/scala-asm-5.0.4-scala-3.jar"/>
+ <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/scaladoc/scala-xml_2.12.0-M4-1.0.5.jar"/>
+ <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/scaladoc/scala-parser-combinators_2.12.0-M4-1.0.4.jar"/>
+ <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/partest/scala-partest_2.12.0-M4-1.0.14.jar"/>
<classpathentry kind="output" path="build-quick-scaladoc"/>
</classpath>
diff --git a/src/eclipse/test-junit/.classpath b/src/eclipse/test-junit/.classpath
index 995d94aa91..3635c85112 100644
--- a/src/eclipse/test-junit/.classpath
+++ b/src/eclipse/test-junit/.classpath
@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="test-junit"/>
+ <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/asm/scala-asm-5.0.4-scala-3.jar"/>
<classpathentry kind="var" path="SCALA_BASEDIR/lib/ant/ant.jar"/>
- <classpathentry kind="var" path="M2_REPO/junit/junit/4.11/junit-4.11.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/reflect"/>
<classpathentry combineaccessrules="false" kind="src" path="/scala-library"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/scala-compiler"/>
<classpathentry combineaccessrules="false" kind="src" path="/repl"/>
- <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/asm/scala-asm-5.0.4-scala-3.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/partest-extras"/>
<classpathentry combineaccessrules="false" kind="src" path="/scaladoc"/>
- <classpathentry kind="var" path="M2_REPO/org/scala-lang/modules/scala-xml_2.12.0-M2/1.0.5/scala-xml_2.12.0-M2-1.0.5.jar"/>
+ <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/scaladoc/scala-xml_2.12.0-M4-1.0.5.jar"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="output" path="build-test-junit"/>
</classpath>
diff --git a/src/eclipse/update-workspace.sh b/src/eclipse/update-workspace.sh
new file mode 100755
index 0000000000..24382d1445
--- /dev/null
+++ b/src/eclipse/update-workspace.sh
@@ -0,0 +1,72 @@
+#!/bin/bash
+
+function usage() {
+ echo "$0 scala_checkout_dir [workspace_dir]"
+ echo "\n Add necessary path variables to Eclipse workspace settings for Scalac to build"
+}
+
+METADATA_DIR=`pwd`/.metadata
+
+if [ $# -lt 1 ]; then
+ echo "Need the Scala directory checkout as argument"
+ exit 1
+fi
+
+SCALA_DIR=$1
+
+if [ ! -z $2 ]; then
+ METADATA_DIR=$2/.metadata
+fi
+
+if [ ! -d $METADATA_DIR ]; then
+ echo "$METADATA_DIR is not a directory"
+ exit 1
+fi
+
+echo "Using metadata directory $METADATA_DIR and Scala checkout $SCALA_DIR"
+
+CORE_PREFS=$METADATA_DIR/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs
+if [ ! -f $CORE_PREFS ]; then
+ echo "Couldn't find $CORE_PREFS. Is $METADATA_DIR an Eclipse workspace?"
+ exit 1
+fi
+echo -e "Workspace preferences:\t$CORE_PREFS"
+
+JDT_PREFS=$METADATA_DIR/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.jdt.core.prefs
+if [ ! -f $JDT_PREFS ]; then
+ echo "Couldn't find $JDT_PREFS. Creating fresh file."
+ touch $JDT_PREFS
+fi
+echo -e "JDT preferences:\t$JDT_PREFS"
+
+# $1 - preference file (will be backed-up before writing)
+# $2 - preference key
+# $3 - preference value
+function updatePref() {
+ mv $1 ${1}_backup
+
+ awk -v key=$2 -v value=$3 '
+ BEGIN {
+ FS="=";
+ OFS="=";
+ prev=""
+ }
+ {
+ if ($1 == key) {
+ prev=$2
+ $2=value
+ }
+ print
+ }
+ END {
+ if (prev) {
+ printf "Updated existing value from %s to %s\n", prev, value > "/dev/stderr"
+ } else {
+ print key,value
+ }
+ }
+ ' ${1}_backup >$1
+}
+
+updatePref $CORE_PREFS "pathvariable.SCALA_BASEDIR" $SCALA_DIR
+updatePref $JDT_PREFS "org.eclipse.jdt.core.classpathVariable.SCALA_BASEDIR" $SCALA_DIR
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/intellij/scala.ipr.SAMPLE b/src/intellij/scala.ipr.SAMPLE
index 8184b0e45b..79ad2808f6 100644
--- a/src/intellij/scala.ipr.SAMPLE
+++ b/src/intellij/scala.ipr.SAMPLE
@@ -77,7 +77,7 @@
<root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang.modules/scala-asm/bundles/scala-asm-5.0.4-scala-3.jar!/" />
<root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang.modules/scala-xml_2.12.0-M3-dc9effe/bundles/scala-xml_2.12.0-M3-dc9effe-1.0.5.jar!/" />
<root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang.modules/scala-parser-combinators_2.12.0-M3-dc9effe/bundles/scala-parser-combinators_2.12.0-M3-dc9effe-1.0.4.jar!/" />
- <root url="jar://$USER_HOME$/.ivy2/cache/jline/jline/jars/jline-2.12.1.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/jline/jline/jars/jline-2.14.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
@@ -100,7 +100,7 @@
<root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang.modules/scala-asm/bundles/scala-asm-5.0.4-scala-3.jar!/" />
<root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang.modules/scala-xml_2.12.0-M3-dc9effe/bundles/scala-xml_2.12.0-M3-dc9effe-1.0.5.jar!/" />
<root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang.modules/scala-parser-combinators_2.12.0-M3-dc9effe/bundles/scala-parser-combinators_2.12.0-M3-dc9effe-1.0.4.jar!/" />
- <root url="jar://$USER_HOME$/.ivy2/cache/jline/jline/jars/jline-2.12.1.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/jline/jline/jars/jline-2.14.1.jar!/" />
<root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang.modules/scala-partest_2.12.0-M3-dc9effe/jars/scala-partest_2.12.0-M3-dc9effe-1.0.13.jar!/" />
<root url="jar://$USER_HOME$/.ivy2/cache/com.googlecode.java-diff-utils/diffutils/jars/diffutils-1.3.0.jar!/" />
<root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/test-interface/jars/test-interface-1.0.jar!/" />
@@ -126,7 +126,7 @@
<root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang.modules/scala-asm/bundles/scala-asm-5.0.4-scala-3.jar!/" />
<root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang.modules/scala-xml_2.12.0-M3-dc9effe/bundles/scala-xml_2.12.0-M3-dc9effe-1.0.5.jar!/" />
<root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang.modules/scala-parser-combinators_2.12.0-M3-dc9effe/bundles/scala-parser-combinators_2.12.0-M3-dc9effe-1.0.4.jar!/" />
- <root url="jar://$USER_HOME$/.ivy2/cache/jline/jline/jars/jline-2.12.1.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/jline/jline/jars/jline-2.14.1.jar!/" />
<root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang.modules/scala-partest_2.12.0-M3-dc9effe/jars/scala-partest_2.12.0-M3-dc9effe-1.0.13.jar!/" />
<root url="jar://$USER_HOME$/.ivy2/cache/com.googlecode.java-diff-utils/diffutils/jars/diffutils-1.3.0.jar!/" />
<root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/test-interface/jars/test-interface-1.0.jar!/" />
@@ -159,7 +159,7 @@
<root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang.modules/scala-asm/bundles/scala-asm-5.0.4-scala-3.jar!/" />
<root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang.modules/scala-xml_2.12.0-M3-dc9effe/bundles/scala-xml_2.12.0-M3-dc9effe-1.0.5.jar!/" />
<root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang.modules/scala-parser-combinators_2.12.0-M3-dc9effe/bundles/scala-parser-combinators_2.12.0-M3-dc9effe-1.0.4.jar!/" />
- <root url="jar://$USER_HOME$/.ivy2/cache/jline/jline/jars/jline-2.12.1.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/jline/jline/jars/jline-2.14.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
@@ -303,7 +303,7 @@
<root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang.modules/scala-asm/bundles/scala-asm-5.0.4-scala-3.jar!/" />
<root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang.modules/scala-xml_2.12.0-M3-dc9effe/bundles/scala-xml_2.12.0-M3-dc9effe-1.0.5.jar!/" />
<root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang.modules/scala-parser-combinators_2.12.0-M3-dc9effe/bundles/scala-parser-combinators_2.12.0-M3-dc9effe-1.0.4.jar!/" />
- <root url="jar://$USER_HOME$/.ivy2/cache/jline/jline/jars/jline-2.12.1.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/jline/jline/jars/jline-2.14.1.jar!/" />
<root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang.modules/scala-partest_2.12.0-M3-dc9effe/jars/scala-partest_2.12.0-M3-dc9effe-1.0.13.jar!/" />
<root url="jar://$USER_HOME$/.ivy2/cache/com.googlecode.java-diff-utils/diffutils/jars/diffutils-1.3.0.jar!/" />
<root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/test-interface/jars/test-interface-1.0.jar!/" />
@@ -312,4 +312,4 @@
<SOURCES />
</library>
</component>
-</project> \ No newline at end of file
+</project>
diff --git a/src/library/rootdoc.txt b/src/library/rootdoc.txt
index 95f9836cc9..d78df01046 100644
--- a/src/library/rootdoc.txt
+++ b/src/library/rootdoc.txt
@@ -37,7 +37,7 @@ Notable packages include:
- [[scala.sys `scala.sys`]] - Interaction with other processes and the operating system
- [[scala.util.matching `scala.util.matching`]] - [[scala.util.matching.Regex Regular expressions]]
-Other packages exist. See the complete list on the left.
+Other packages exist. See the complete list on the right.
Additional parts of the standard library are shipped as separate libraries. These include:
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/Product.scala b/src/library/scala/Product.scala
index 9cd38ed148..f3a96fb333 100644
--- a/src/library/scala/Product.scala
+++ b/src/library/scala/Product.scala
@@ -19,7 +19,7 @@ package scala
*/
trait Product extends Any with Equals {
/** The n^th^ element of this product, 0-based. In other words, for a
- * product `A(x,,1,,, ..., x,,k,,)`, returns `x,,(n+1),,` where `0 < n < k`.
+ * product `A(x,,1,,, ..., x,,k,,)`, returns `x,,(n+1),,` where `0 <= n < k`.
*
* @param n the index of the element to return
* @throws IndexOutOfBoundsException
diff --git a/src/library/scala/Unit.scala b/src/library/scala/Unit.scala
index 397d7b823b..eb6d1d0ddf 100644
--- a/src/library/scala/Unit.scala
+++ b/src/library/scala/Unit.scala
@@ -30,7 +30,7 @@ object Unit extends AnyValCompanion {
* @param x the Unit to be boxed
* @return a scala.runtime.BoxedUnit offering `x` as its underlying value.
*/
- def box(x: Unit): scala.runtime.BoxedUnit = ???
+ def box(x: Unit): scala.runtime.BoxedUnit = scala.runtime.BoxedUnit.UNIT
/** Transform a boxed type into a value type. Note that this
* method is not typesafe: it accepts any Object, but will throw
@@ -40,7 +40,7 @@ object Unit extends AnyValCompanion {
* @throws ClassCastException if the argument is not a scala.runtime.BoxedUnit
* @return the Unit value ()
*/
- def unbox(x: java.lang.Object): Unit = ???
+ def unbox(x: java.lang.Object): Unit = x.asInstanceOf[scala.runtime.BoxedUnit]
/** The String representation of the scala.Unit companion object. */
override def toString = "object scala.Unit"
diff --git a/src/library/scala/collection/JavaConversions.scala b/src/library/scala/collection/JavaConversions.scala
index f9a34f78d5..960e452cdf 100644
--- a/src/library/scala/collection/JavaConversions.scala
+++ b/src/library/scala/collection/JavaConversions.scala
@@ -1,6 +1,6 @@
/* __ *\
** ________ ___ / / ___ Scala API **
-** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
+** / __/ __// _ | / / / _ | (c) 2006-2016, LAMP/EPFL **
** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ **
** /____/\___/_/ |_/____/_/ | | **
** |/ **
@@ -11,10 +11,10 @@ package collection
import convert._
-/** A collection of implicit conversions supporting interoperability between
- * Scala and Java collections.
+/** A variety of implicit conversions supporting interoperability between
+ * Scala and Java collections.
*
- * The following conversions are supported:
+ * The following conversions are supported:
*{{{
* scala.collection.Iterable <=> java.lang.Iterable
* scala.collection.Iterable <=> java.util.Collection
@@ -24,8 +24,8 @@ import convert._
* scala.collection.mutable.Map <=> java.util.{ Map, Dictionary }
* scala.collection.concurrent.Map <=> java.util.concurrent.ConcurrentMap
*}}}
- * In all cases, converting from a source type to a target type and back
- * again will return the original source object, eg.
+ * In all cases, converting from a source type to a target type and back
+ * again will return the original source object:
*
*{{{
* import scala.collection.JavaConversions._
@@ -45,8 +45,16 @@ import convert._
* java.util.Properties => scala.collection.mutable.Map[String, String]
*}}}
*
+ * The transparent conversions provided here are considered
+ * fragile because they can result in unexpected behavior and performance.
+ *
+ * Therefore, this API has been deprecated and `JavaConverters` should be
+ * used instead. `JavaConverters` provides the same conversions, but through
+ * extension methods.
+ *
* @author Miles Sabin
* @author Martin Odersky
* @since 2.8
*/
+@deprecated("Use JavaConverters", since="2.12")
object JavaConversions extends WrapAsScala with WrapAsJava
diff --git a/src/library/scala/collection/JavaConverters.scala b/src/library/scala/collection/JavaConverters.scala
index 58fbc5afa5..d48a1764e9 100644
--- a/src/library/scala/collection/JavaConverters.scala
+++ b/src/library/scala/collection/JavaConverters.scala
@@ -1,6 +1,6 @@
/* __ *\
** ________ ___ / / ___ Scala API **
-** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
+** / __/ __// _ | / / / _ | (c) 2006-2016, LAMP/EPFL **
** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ **
** /____/\___/_/ |_/____/_/ | | **
** |/ **
@@ -11,14 +11,12 @@ package collection
import convert._
-// TODO: I cleaned all this documentation up in JavaConversions, but the
-// documentation in here is basically the pre-cleaned-up version with minor
-// additions. Would be nice to have in one place.
-
-/** A collection of decorators that allow converting between
- * Scala and Java collections using `asScala` and `asJava` methods.
+/** A variety of decorators that enable converting between
+ * Scala and Java collections using extension methods, `asScala` and `asJava`.
+ *
+ * The extension methods return adapters for the corresponding API.
*
- * The following conversions are supported via `asJava`, `asScala`
+ * The following conversions are supported via `asScala` and `asJava`:
*{{{
* scala.collection.Iterable <=> java.lang.Iterable
* scala.collection.Iterator <=> java.util.Iterator
@@ -27,25 +25,14 @@ import convert._
* scala.collection.mutable.Map <=> java.util.Map
* scala.collection.mutable.concurrent.Map <=> java.util.concurrent.ConcurrentMap
*}}}
- * In all cases, converting from a source type to a target type and back
- * again will return the original source object, e.g.
- * {{{
- * import scala.collection.JavaConverters._
- *
- * val sl = new scala.collection.mutable.ListBuffer[Int]
- * val jl : java.util.List[Int] = sl.asJava
- * val sl2 : scala.collection.mutable.Buffer[Int] = jl.asScala
- * assert(sl eq sl2)
- * }}}
- * The following conversions are also supported, but the
- * direction from Scala to Java is done by the more specifically named methods:
- * `asJavaCollection`, `asJavaEnumeration`, `asJavaDictionary`.
+ * The following conversions are supported via `asScala` and through
+ * specially-named extension methods to convert to Java collections, as shown:
*{{{
- * scala.collection.Iterable <=> java.util.Collection
- * scala.collection.Iterator <=> java.util.Enumeration
- * scala.collection.mutable.Map <=> java.util.Dictionary
+ * scala.collection.Iterable <=> java.util.Collection (via asJavaCollection)
+ * scala.collection.Iterator <=> java.util.Enumeration (via asJavaEnumeration)
+ * scala.collection.mutable.Map <=> java.util.Dictionary (via asJavaDictionary)
*}}}
- * In addition, the following one way conversions are provided via `asJava`:
+ * In addition, the following one-way conversions are provided via `asJava`:
*{{{
* scala.collection.Seq => java.util.List
* scala.collection.mutable.Seq => java.util.List
@@ -56,6 +43,31 @@ import convert._
*{{{
* java.util.Properties => scala.collection.mutable.Map
*}}}
+ * In all cases, converting from a source type to a target type and back
+ * again will return the original source object. For example:
+ * {{{
+ * import scala.collection.JavaConverters._
+ *
+ * val source = new scala.collection.mutable.ListBuffer[Int]
+ * val target: java.util.List[Int] = source.asJava
+ * val other: scala.collection.mutable.Buffer[Int] = target.asScala
+ * assert(source eq other)
+ * }}}
+ * Alternatively, the conversion methods have descriptive names and can be invoked explicitly.
+ * {{{
+ * scala> val vs = java.util.Arrays.asList("hi", "bye")
+ * vs: java.util.List[String] = [hi, bye]
+ *
+ * scala> val ss = asScalaIterator(vs.iterator)
+ * ss: Iterator[String] = non-empty iterator
+ *
+ * scala> .toList
+ * res0: List[String] = List(hi, bye)
+ *
+ * scala> val ss = asScalaBuffer(vs)
+ * ss: scala.collection.mutable.Buffer[String] = Buffer(hi, bye)
+ * }}}
+ *
* @since 2.8.1
*/
object JavaConverters extends DecorateAsJava with DecorateAsScala
diff --git a/src/library/scala/collection/concurrent/TrieMap.scala b/src/library/scala/collection/concurrent/TrieMap.scala
index d113cbfcdf..5dc01547e6 100644
--- a/src/library/scala/collection/concurrent/TrieMap.scala
+++ b/src/library/scala/collection/concurrent/TrieMap.scala
@@ -1106,14 +1106,14 @@ private[concurrent] case object TrieMapSerializationEnd
private[concurrent] object Debug {
- import scala.collection._
+ import JavaConverters._
lazy val logbuffer = new java.util.concurrent.ConcurrentLinkedQueue[AnyRef]
def log(s: AnyRef) = logbuffer.add(s)
def flush() {
- for (s <- JavaConversions.asScalaIterator(logbuffer.iterator())) Console.out.println(s.toString)
+ for (s <- logbuffer.iterator().asScala) Console.out.println(s.toString)
logbuffer.clear()
}
diff --git a/src/library/scala/collection/convert/AsJavaConverters.scala b/src/library/scala/collection/convert/AsJavaConverters.scala
new file mode 100644
index 0000000000..c7c1fb9c74
--- /dev/null
+++ b/src/library/scala/collection/convert/AsJavaConverters.scala
@@ -0,0 +1,262 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2016, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+package collection
+package convert
+
+import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc }
+
+/** Defines converter methods from Scala to Java collections. */
+trait AsJavaConverters {
+ import Wrappers._
+
+ /**
+ * Converts a Scala `Iterator` to a Java `Iterator`.
+ *
+ * The returned Java `Iterator` is backed by the provided Scala `Iterator` and any side-effects of
+ * using it via the Java interface will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Iterator` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.asScalaIterator]](java.util.Iterator)` then the original Java `Iterator` will
+ * be returned.
+ *
+ * @param i The Scala `Iterator` to be converted.
+ * @return A Java `Iterator` view of the argument.
+ */
+ def asJavaIterator[A](i: Iterator[A]): ju.Iterator[A] = i match {
+ case null => null
+ case JIteratorWrapper(wrapped) => wrapped.asInstanceOf[ju.Iterator[A]]
+ case _ => IteratorWrapper(i)
+ }
+
+ /**
+ * Converts a Scala `Iterator` to a Java `Enumeration`.
+ *
+ * The returned Java `Enumeration` is backed by the provided Scala `Iterator` and any side-effects
+ * of using it via the Java interface will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Iterator` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.enumerationAsScalaIterator]](java.util.Enumeration)` then the original Java
+ * `Enumeration` will be returned.
+ *
+ * @param i The Scala `Iterator` to be converted.
+ * @return A Java `Enumeration` view of the argument.
+ */
+ def asJavaEnumeration[A](i: Iterator[A]): ju.Enumeration[A] = i match {
+ case null => null
+ case JEnumerationWrapper(wrapped) => wrapped.asInstanceOf[ju.Enumeration[A]]
+ case _ => IteratorWrapper(i)
+ }
+
+ /**
+ * Converts a Scala `Iterable` to a Java `Iterable`.
+ *
+ * The returned Java `Iterable` is backed by the provided Scala `Iterable` and any side-effects of
+ * using it via the Java interface will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Iterable` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.iterableAsScalaIterable]](java.lang.Iterable)` then the original Java
+ * `Iterable` will be returned.
+ *
+ * @param i The Scala `Iterable` to be converted.
+ * @return A Java `Iterable` view of the argument.
+ */
+ def asJavaIterable[A](i: Iterable[A]): jl.Iterable[A] = i match {
+ case null => null
+ case JIterableWrapper(wrapped) => wrapped.asInstanceOf[jl.Iterable[A]]
+ case _ => IterableWrapper(i)
+ }
+
+ /**
+ * Converts a Scala `Iterable` to an immutable Java `Collection`.
+ *
+ * If the Scala `Iterable` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.collectionAsScalaIterable]](java.util.Collection)` then the original Java
+ * `Collection` will be returned.
+ *
+ * @param i The Scala `Iterable` to be converted.
+ * @return A Java `Collection` view of the argument.
+ */
+ def asJavaCollection[A](i: Iterable[A]): ju.Collection[A] = i match {
+ case null => null
+ case JCollectionWrapper(wrapped) => wrapped.asInstanceOf[ju.Collection[A]]
+ case _ => new IterableWrapper(i)
+ }
+
+ /**
+ * Converts a Scala mutable `Buffer` to a Java List.
+ *
+ * The returned Java List is backed by the provided Scala `Buffer` and any side-effects of using
+ * it via the Java interface will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Buffer` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.asScalaBuffer]](java.util.List)` then the original Java `List` will be
+ * returned.
+ *
+ * @param b The Scala `Buffer` to be converted.
+ * @return A Java `List` view of the argument.
+ */
+ def bufferAsJavaList[A](b: mutable.Buffer[A]): ju.List[A] = b match {
+ case null => null
+ case JListWrapper(wrapped) => wrapped
+ case _ => new MutableBufferWrapper(b)
+ }
+
+ /**
+ * Converts a Scala mutable `Seq` to a Java `List`.
+ *
+ * The returned Java `List` is backed by the provided Scala `Seq` and any side-effects of using it
+ * via the Java interface will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Seq` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.asScalaBuffer]](java.util.List)` then the original Java `List` will be
+ * returned.
+ *
+ * @param s The Scala `Seq` to be converted.
+ * @return A Java `List` view of the argument.
+ */
+ def mutableSeqAsJavaList[A](s: mutable.Seq[A]): ju.List[A] = s match {
+ case null => null
+ case JListWrapper(wrapped) => wrapped
+ case _ => new MutableSeqWrapper(s)
+ }
+
+ /**
+ * Converts a Scala `Seq` to a Java `List`.
+ *
+ * The returned Java `List` is backed by the provided Scala `Seq` and any side-effects of using it
+ * via the Java interface will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Seq` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.asScalaBuffer]](java.util.List)` then the original Java `List` will be
+ * returned.
+ *
+ * @param s The Scala `Seq` to be converted.
+ * @return A Java `List` view of the argument.
+ */
+ def seqAsJavaList[A](s: Seq[A]): ju.List[A] = s match {
+ case null => null
+ case JListWrapper(wrapped) => wrapped.asInstanceOf[ju.List[A]]
+ case _ => new SeqWrapper(s)
+ }
+
+ /**
+ * Converts a Scala mutable `Set` to a Java `Set`.
+ *
+ * The returned Java `Set` is backed by the provided Scala `Set` and any side-effects of using it
+ * via the Java interface will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Set` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.asScalaSet]](java.util.Set)` then the original Java `Set` will be returned.
+ *
+ * @param s The Scala mutable `Set` to be converted.
+ * @return A Java `Set` view of the argument.
+ */
+ def mutableSetAsJavaSet[A](s: mutable.Set[A]): ju.Set[A] = s match {
+ case null => null
+ case JSetWrapper(wrapped) => wrapped
+ case _ => new MutableSetWrapper(s)
+ }
+
+ /**
+ * Converts a Scala `Set` to a Java `Set`.
+ *
+ * The returned Java `Set` is backed by the provided Scala `Set` and any side-effects of using it
+ * via the Java interface will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Set` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.asScalaSet]](java.util.Set)` then the original Java `Set` will be returned.
+ *
+ * @param s The Scala `Set` to be converted.
+ * @return A Java `Set` view of the argument.
+ */
+ def setAsJavaSet[A](s: Set[A]): ju.Set[A] = s match {
+ case null => null
+ case JSetWrapper(wrapped) => wrapped
+ case _ => new SetWrapper(s)
+ }
+
+ /**
+ * Converts a Scala mutable `Map` to a Java `Map`.
+ *
+ * The returned Java `Map` is backed by the provided Scala `Map` and any side-effects of using it
+ * via the Java interface will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Map` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.mapAsScalaMap]](java.util.Map)` then the original Java `Map` will be
+ * returned.
+ *
+ * @param m The Scala mutable `Map` to be converted.
+ * @return A Java `Map` view of the argument.
+ */
+ def mutableMapAsJavaMap[A, B](m: mutable.Map[A, B]): ju.Map[A, B] = m match {
+ case null => null
+ case JMapWrapper(wrapped) => wrapped
+ case _ => new MutableMapWrapper(m)
+ }
+
+ /**
+ * Converts a Scala mutable `Map` to a Java `Dictionary`.
+ *
+ * The returned Java `Dictionary` is backed by the provided Scala `Dictionary` and any
+ * side-effects of using it via the Java interface will be visible via the Scala interface and
+ * vice versa.
+ *
+ * If the Scala `Dictionary` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.dictionaryAsScalaMap]](java.util.Dictionary)` then the original Java
+ * `Dictionary` will be returned.
+ *
+ * @param m The Scala `Map` to be converted.
+ * @return A Java `Dictionary` view of the argument.
+ */
+ def asJavaDictionary[A, B](m: mutable.Map[A, B]): ju.Dictionary[A, B] = m match {
+ case null => null
+ case JDictionaryWrapper(wrapped) => wrapped
+ case _ => new DictionaryWrapper(m)
+ }
+
+ /**
+ * Converts a Scala `Map` to a Java `Map`.
+ *
+ * The returned Java `Map` is backed by the provided Scala `Map` and any side-effects of using it
+ * via the Java interface will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Map` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.mapAsScalaMap]](java.util.Map)` then the original Java `Map` will be
+ * returned.
+ *
+ * @param m The Scala `Map` to be converted.
+ * @return A Java `Map` view of the argument.
+ */
+ def mapAsJavaMap[A, B](m: Map[A, B]): ju.Map[A, B] = m match {
+ case null => null
+ case JMapWrapper(wrapped) => wrapped.asInstanceOf[ju.Map[A, B]]
+ case _ => new MapWrapper(m)
+ }
+
+ /**
+ * Converts a Scala mutable `concurrent.Map` to a Java `ConcurrentMap`.
+ *
+ * The returned Java `ConcurrentMap` is backed by the provided Scala `concurrent.Map` and any
+ * side-effects of using it via the Java interface will be visible via the Scala interface and
+ * vice versa.
+ *
+ * If the Scala `concurrent.Map` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.mapAsScalaConcurrentMap]](java.util.concurrent.ConcurrentMap)` then the
+ * original Java `ConcurrentMap` will be returned.
+ *
+ * @param m The Scala `concurrent.Map` to be converted.
+ * @return A Java `ConcurrentMap` view of the argument.
+ */
+ def mapAsJavaConcurrentMap[A, B](m: concurrent.Map[A, B]): juc.ConcurrentMap[A, B] = m match {
+ case null => null
+ case JConcurrentMapWrapper(wrapped) => wrapped
+ case _ => new ConcurrentMapWrapper(m)
+ }
+}
diff --git a/src/library/scala/collection/convert/AsScalaConverters.scala b/src/library/scala/collection/convert/AsScalaConverters.scala
new file mode 100644
index 0000000000..f9e38797e1
--- /dev/null
+++ b/src/library/scala/collection/convert/AsScalaConverters.scala
@@ -0,0 +1,207 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2016, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+package collection
+package convert
+
+import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc }
+
+/** Defines converter methods from Java to Scala collections. */
+trait AsScalaConverters {
+ import Wrappers._
+
+ /**
+ * Converts a Java `Iterator` to a Scala `Iterator`.
+ *
+ * The returned Scala `Iterator` is backed by the provided Java `Iterator` and any side-effects of
+ * using it via the Scala interface will be visible via the Java interface and vice versa.
+ *
+ * If the Java `Iterator` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.asJavaIterator]](scala.collection.Iterator)` then the original Scala
+ * `Iterator` will be returned.
+ *
+ * @param i The Java `Iterator` to be converted.
+ * @return A Scala `Iterator` view of the argument.
+ */
+ def asScalaIterator[A](i: ju.Iterator[A]): Iterator[A] = i match {
+ case null => null
+ case IteratorWrapper(wrapped) => wrapped
+ case _ => JIteratorWrapper(i)
+ }
+
+ /**
+ * Converts a Java `Enumeration` to a Scala `Iterator`.
+ *
+ * The returned Scala `Iterator` is backed by the provided Java `Enumeration` and any side-effects
+ * of using it via the Scala interface will be visible via the Java interface and vice versa.
+ *
+ * If the Java `Enumeration` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.asJavaEnumeration]](scala.collection.Iterator)` then the original Scala
+ * `Iterator` will be returned.
+ *
+ * @param i The Java `Enumeration` to be converted.
+ * @return A Scala `Iterator` view of the argument.
+ */
+ def enumerationAsScalaIterator[A](i: ju.Enumeration[A]): Iterator[A] = i match {
+ case null => null
+ case IteratorWrapper(wrapped) => wrapped
+ case _ => JEnumerationWrapper(i)
+ }
+
+ /**
+ * Converts a Java `Iterable` to a Scala `Iterable`.
+ *
+ * The returned Scala `Iterable` is backed by the provided Java `Iterable` and any side-effects of
+ * using it via the Scala interface will be visible via the Java interface and vice versa.
+ *
+ * If the Java `Iterable` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.asJavaIterable]](scala.collection.Iterable) then the original Scala
+ * `Iterable` will be returned.
+ *
+ * @param i The Java `Iterable` to be converted.
+ * @return A Scala `Iterable` view of the argument.
+ */
+ def iterableAsScalaIterable[A](i: jl.Iterable[A]): Iterable[A] = i match {
+ case null => null
+ case IterableWrapper(wrapped) => wrapped
+ case _ => JIterableWrapper(i)
+ }
+
+ /**
+ * Converts a Java `Collection` to an Scala `Iterable`.
+ *
+ * If the Java `Collection` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.asJavaCollection]](scala.collection.Iterable)` then the original Scala
+ * `Iterable` will be returned.
+ *
+ * @param i The Java `Collection` to be converted.
+ * @return A Scala `Iterable` view of the argument.
+ */
+ def collectionAsScalaIterable[A](i: ju.Collection[A]): Iterable[A] = i match {
+ case null => null
+ case IterableWrapper(wrapped) => wrapped
+ case _ => JCollectionWrapper(i)
+ }
+
+ /**
+ * Converts a Java `List` to a Scala mutable `Buffer`.
+ *
+ * The returned Scala `Buffer` is backed by the provided Java `List` and any side-effects of using
+ * it via the Scala interface will be visible via the Java interface and vice versa.
+ *
+ * If the Java `List` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.bufferAsJavaList]](scala.collection.mutable.Buffer)` then the original Scala
+ * `Buffer` will be returned.
+ *
+ * @param l The Java `List` to be converted.
+ * @return A Scala mutable `Buffer` view of the argument.
+ */
+ def asScalaBuffer[A](l: ju.List[A]): mutable.Buffer[A] = l match {
+ case null => null
+ case MutableBufferWrapper(wrapped) => wrapped
+ case _ => new JListWrapper(l)
+ }
+
+ /**
+ * Converts a Java `Set` to a Scala mutable `Set`.
+ *
+ * The returned Scala `Set` is backed by the provided Java `Set` and any side-effects of using it
+ * via the Scala interface will be visible via the Java interface and vice versa.
+ *
+ * If the Java `Set` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.mutableSetAsJavaSet]](scala.collection.mutable.Set)` then the original Scala
+ * `Set` will be returned.
+ *
+ * @param s The Java `Set` to be converted.
+ * @return A Scala mutable `Set` view of the argument.
+ */
+ def asScalaSet[A](s: ju.Set[A]): mutable.Set[A] = s match {
+ case null => null
+ case MutableSetWrapper(wrapped) => wrapped
+ case _ => new JSetWrapper(s)
+ }
+
+ /**
+ * Converts a Java `Map` to a Scala mutable `Map`.
+ *
+ * The returned Scala `Map` is backed by the provided Java `Map` and any side-effects of using it
+ * via the Scala interface will be visible via the Java interface and vice versa.
+ *
+ * If the Java `Map` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.mutableMapAsJavaMap]](scala.collection.mutable.Map)` then the original Scala
+ * `Map` will be returned.
+ *
+ * If the wrapped map is synchronized (e.g. from `java.util.Collections.synchronizedMap`), it is
+ * your responsibility to wrap all non-atomic operations with `underlying.synchronized`.
+ * This includes `get`, as `java.util.Map`'s API does not allow for an atomic `get` when `null`
+ * values may be present.
+ *
+ * @param m The Java `Map` to be converted.
+ * @return A Scala mutable `Map` view of the argument.
+ */
+ def mapAsScalaMap[A, B](m: ju.Map[A, B]): mutable.Map[A, B] = m match {
+ case null => null
+ case MutableMapWrapper(wrapped) => wrapped
+ case _ => new JMapWrapper(m)
+ }
+
+ /**
+ * Converts a Java `ConcurrentMap` to a Scala mutable `ConcurrentMap`.
+ *
+ * The returned Scala `ConcurrentMap` is backed by the provided Java `ConcurrentMap` and any
+ * side-effects of using it via the Scala interface will be visible via the Java interface and
+ * vice versa.
+ *
+ * If the Java `ConcurrentMap` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.mapAsJavaConcurrentMap]](scala.collection.mutable.ConcurrentMap)`
+ * then the original Scala `ConcurrentMap` will be returned.
+ *
+ * @param m The Java `ConcurrentMap` to be converted.
+ * @return A Scala mutable `ConcurrentMap` view of the argument.
+ */
+ def mapAsScalaConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): concurrent.Map[A, B] = m match {
+ case null => null
+ case cmw: ConcurrentMapWrapper[_, _] => cmw.underlying
+ case _ => new JConcurrentMapWrapper(m)
+ }
+
+ /**
+ * Converts a Java `Dictionary` to a Scala mutable `Map`.
+ *
+ * The returned Scala `Map` is backed by the provided Java `Dictionary` and any side-effects of
+ * using it via the Scala interface will be visible via the Java interface and vice versa.
+ *
+ * If the Java `Dictionary` was previously obtained from an implicit or explicit call of
+ * `[[JavaConverters.asJavaDictionary]](scala.collection.mutable.Map)` then the original
+ * Scala `Map` will be returned.
+ *
+ * @param p The Java `Dictionary` to be converted.
+ * @return A Scala mutable `Map` view of the argument.
+ */
+ def dictionaryAsScalaMap[A, B](p: ju.Dictionary[A, B]): mutable.Map[A, B] = p match {
+ case null => null
+ case DictionaryWrapper(wrapped) => wrapped
+ case _ => new JDictionaryWrapper(p)
+ }
+
+ /**
+ * Converts a Java `Properties` to a Scala mutable `Map[String, String]`.
+ *
+ * The returned Scala `Map[String, String]` is backed by the provided Java `Properties` and any
+ * side-effects of using it via the Scala interface will be visible via the Java interface and
+ * vice versa.
+ *
+ * @param p The Java `Properties` to be converted.
+ * @return A Scala mutable `Map[String, String]` view of the argument.
+ */
+ def propertiesAsScalaMap(p: ju.Properties): mutable.Map[String, String] = p match {
+ case null => null
+ case _ => new JPropertiesWrapper(p)
+ }
+}
diff --git a/src/library/scala/collection/convert/DecorateAsJava.scala b/src/library/scala/collection/convert/DecorateAsJava.scala
index 0ed67a86d7..8371804b91 100644
--- a/src/library/scala/collection/convert/DecorateAsJava.scala
+++ b/src/library/scala/collection/convert/DecorateAsJava.scala
@@ -1,6 +1,6 @@
/* __ *\
** ________ ___ / / ___ Scala API **
-** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
+** / __/ __// _ | / / / _ | (c) 2006-2016, LAMP/EPFL **
** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ **
** /____/\___/_/ |_/____/_/ | | **
** |/ **
@@ -12,289 +12,97 @@ package convert
import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc }
import Decorators._
-import WrapAsJava._
import scala.language.implicitConversions
-
-/** A collection of decorators that allow converting between
- * Scala and Java collections using `asScala` and `asJava` methods.
- *
- * The following conversions are supported via `asJava`, `asScala`
- *{{{
- * scala.collection.Iterable <=> java.lang.Iterable
- * scala.collection.Iterator <=> java.util.Iterator
- * scala.collection.mutable.Buffer <=> java.util.List
- * scala.collection.mutable.Set <=> java.util.Set
- * scala.collection.mutable.Map <=> java.util.Map
- * scala.collection.mutable.concurrent.Map <=> java.util.concurrent.ConcurrentMap
- *}}}
- * In all cases, converting from a source type to a target type and back
- * again will return the original source object, e.g.
- * {{{
- * import scala.collection.JavaConverters._
- *
- * val sl = new scala.collection.mutable.ListBuffer[Int]
- * val jl : java.util.List[Int] = sl.asJava
- * val sl2 : scala.collection.mutable.Buffer[Int] = jl.asScala
- * assert(sl eq sl2)
- * }}}
- * The following conversions are also supported, but the
- * direction from Scala to Java is done by the more specifically named methods:
- * `asJavaCollection`, `asJavaEnumeration`, `asJavaDictionary`.
- *{{{
- * scala.collection.Iterable <=> java.util.Collection
- * scala.collection.Iterator <=> java.util.Enumeration
- * scala.collection.mutable.Map <=> java.util.Dictionary
- *}}}
- * In addition, the following one way conversions are provided via `asJava`:
- *{{{
- * scala.collection.Seq => java.util.List
- * scala.collection.mutable.Seq => java.util.List
- * scala.collection.Set => java.util.Set
- * scala.collection.Map => java.util.Map
- *}}}
- * The following one way conversion is provided via `asScala`:
- *{{{
- * java.util.Properties => scala.collection.mutable.Map
- *}}}
- * @since 2.8.1
- */
-trait DecorateAsJava {
+/** Defines `asJava` extension methods for [[JavaConverters]]. */
+trait DecorateAsJava extends AsJavaConverters {
/**
- * Adds an `asJava` method that implicitly converts a Scala `Iterator` to a
- * Java `Iterator`. The returned Java `Iterator` is backed by the provided Scala
- * `Iterator` and any side-effects of using it via the Java interface will
- * be visible via the Scala interface and vice versa.
- *
- * If the Scala `Iterator` was previously obtained from an implicit or explicit
- * call of `asIterator(java.util.Iterator)` then the original Java `Iterator`
- * will be returned by the `asJava` method.
- *
- * @param i The `Iterator` to be converted.
- * @return An object with an `asJava` method that returns a Java `Iterator` view of the argument.
+ * Adds an `asJava` method that implicitly converts a Scala `Iterator` to a Java `Iterator`.
+ * See [[asJavaIterator]].
*/
implicit def asJavaIteratorConverter[A](i : Iterator[A]): AsJava[ju.Iterator[A]] =
new AsJava(asJavaIterator(i))
/**
- * Adds an `asJavaEnumeration` method that implicitly converts a Scala
- * `Iterator` to a Java `Enumeration`. The returned Java `Enumeration` is
- * backed by the provided Scala `Iterator` and any side-effects of using
- * it via the Java interface will be visible via the Scala interface and
- * vice versa.
- *
- * If the Scala `Iterator` was previously obtained from an implicit or
- * explicit call of `asIterator(java.util.Enumeration)` then the
- * original Java `Enumeration` will be returned.
- *
- * @param i The `Iterator` to be converted.
- * @return An object with an `asJavaEnumeration` method that returns a Java
- * `Enumeration` view of the argument.
+ * Adds an `asJavaEnumeration` method that implicitly converts a Scala `Iterator` to a Java
+ * `Enumeration`. See [[asJavaEnumeration]].
*/
implicit def asJavaEnumerationConverter[A](i : Iterator[A]): AsJavaEnumeration[A] =
new AsJavaEnumeration(i)
/**
- * Adds an `asJava` method that implicitly converts a Scala `Iterable` to
- * a Java `Iterable`.
- *
- * The returned Java `Iterable` is backed by the provided Scala `Iterable`
- * and any side-effects of using it via the Java interface will be visible
- * via the Scala interface and vice versa.
- *
- * If the Scala `Iterable` was previously obtained from an implicit or
- * explicit call of `asIterable(java.lang.Iterable)` then the original
- * Java `Iterable` will be returned.
- *
- * @param i The `Iterable` to be converted.
- * @return An object with an `asJavaCollection` method that returns a Java
- * `Iterable` view of the argument.
+ * Adds an `asJava` method that implicitly converts a Scala `Iterable` to a Java `Iterable`.
+ * See [[asJavaIterable]].
*/
implicit def asJavaIterableConverter[A](i : Iterable[A]): AsJava[jl.Iterable[A]] =
new AsJava(asJavaIterable(i))
/**
- * Adds an `asJavaCollection` method that implicitly converts a Scala
- * `Iterable` to an immutable Java `Collection`.
- *
- * If the Scala `Iterable` was previously obtained from an implicit or
- * explicit call of `asSizedIterable(java.util.Collection)` then the
- * original Java `Collection` will be returned.
- *
- * @param i The `SizedIterable` to be converted.
- * @return An object with an `asJava` method that returns a Java
- * `Collection` view of the argument.
+ * Adds an `asJavaCollection` method that implicitly converts a Scala `Iterable` to an immutable
+ * Java `Collection`. See [[asJavaCollection]].
*/
implicit def asJavaCollectionConverter[A](i : Iterable[A]): AsJavaCollection[A] =
new AsJavaCollection(i)
/**
- * Adds an `asJava` method that implicitly converts a Scala mutable `Buffer`
- * to a Java `List`.
- *
- * The returned Java `List` is backed by the provided Scala `Buffer` and any
- * side-effects of using it via the Java interface will be visible via the
- * Scala interface and vice versa.
- *
- * If the Scala `Buffer` was previously obtained from an implicit or explicit
- * call of `asBuffer(java.util.List)` then the original Java `List` will be
- * returned.
- *
- * @param b The `Buffer` to be converted.
- * @return An object with an `asJava` method that returns a Java `List` view
- * of the argument.
+ * Adds an `asJava` method that implicitly converts a Scala mutable `Buffer` to a Java `List`.
+ * See [[bufferAsJavaList]].
*/
implicit def bufferAsJavaListConverter[A](b : mutable.Buffer[A]): AsJava[ju.List[A]] =
new AsJava(bufferAsJavaList(b))
/**
- * Adds an `asJava` method that implicitly converts a Scala mutable `Seq`
- * to a Java `List`.
- *
- * The returned Java `List` is backed by the provided Scala `Seq` and any
- * side-effects of using it via the Java interface will be visible via the
- * Scala interface and vice versa.
- *
- * If the Scala `Seq` was previously obtained from an implicit or explicit
- * call of `asSeq(java.util.List)` then the original Java `List` will be
- * returned.
- *
- * @param b The `Seq` to be converted.
- * @return An object with an `asJava` method that returns a Java `List`
- * view of the argument.
+ * Adds an `asJava` method that implicitly converts a Scala mutable `Seq` to a Java `List`.
+ * See [[mutableSeqAsJavaList]].
*/
implicit def mutableSeqAsJavaListConverter[A](b : mutable.Seq[A]): AsJava[ju.List[A]] =
new AsJava(mutableSeqAsJavaList(b))
/**
- * Adds an `asJava` method that implicitly converts a Scala `Seq` to a
- * Java `List`.
- *
- * The returned Java `List` is backed by the provided Scala `Seq` and any
- * side-effects of using it via the Java interface will be visible via the
- * Scala interface and vice versa.
- *
- * If the Scala `Seq` was previously obtained from an implicit or explicit
- * call of `asSeq(java.util.List)` then the original Java `List` will be
- * returned.
- *
- * @param b The `Seq` to be converted.
- * @return An object with an `asJava` method that returns a Java `List`
- * view of the argument.
+ * Adds an `asJava` method that implicitly converts a Scala `Seq` to a Java `List`.
+ * See [[seqAsJavaList]].
*/
implicit def seqAsJavaListConverter[A](b : Seq[A]): AsJava[ju.List[A]] =
new AsJava(seqAsJavaList(b))
/**
- * Adds an `asJava` method that implicitly converts a Scala mutable `Set`>
- * to a Java `Set`.
- *
- * The returned Java `Set` is backed by the provided Scala `Set` and any
- * side-effects of using it via the Java interface will be visible via
- * the Scala interface and vice versa.
- *
- * If the Scala `Set` was previously obtained from an implicit or explicit
- * call of `asSet(java.util.Set)` then the original Java `Set` will be
- * returned.
- *
- * @param s The `Set` to be converted.
- * @return An object with an `asJava` method that returns a Java `Set` view
- * of the argument.
+ * Adds an `asJava` method that implicitly converts a Scala mutable `Set` to a Java `Set`.
+ * See [[mutableSetAsJavaSet]].
*/
implicit def mutableSetAsJavaSetConverter[A](s : mutable.Set[A]): AsJava[ju.Set[A]] =
new AsJava(mutableSetAsJavaSet(s))
/**
- * Adds an `asJava` method that implicitly converts a Scala `Set` to a
- * Java `Set`.
- *
- * The returned Java `Set` is backed by the provided Scala `Set` and any
- * side-effects of using it via the Java interface will be visible via
- * the Scala interface and vice versa.
- *
- * If the Scala `Set` was previously obtained from an implicit or explicit
- * call of `asSet(java.util.Set)` then the original Java `Set` will be
- * returned.
- *
- * @param s The `Set` to be converted.
- * @return An object with an `asJava` method that returns a Java `Set` view
- * of the argument.
+ * Adds an `asJava` method that implicitly converts a Scala `Set` to a Java `Set`.
+ * See [[setAsJavaSet]].
*/
implicit def setAsJavaSetConverter[A](s : Set[A]): AsJava[ju.Set[A]] =
new AsJava(setAsJavaSet(s))
/**
- * Adds an `asJava` method that implicitly converts a Scala mutable `Map`
- * to a Java `Map`.
- *
- * The returned Java `Map` is backed by the provided Scala `Map` and any
- * side-effects of using it via the Java interface will be visible via the
- * Scala interface and vice versa.
- *
- * If the Scala `Map` was previously obtained from an implicit or explicit
- * call of `asMap(java.util.Map)` then the original Java `Map` will be
- * returned.
- *
- * @param m The `Map` to be converted.
- * @return An object with an `asJava` method that returns a Java `Map` view
- * of the argument.
+ * Adds an `asJava` method that implicitly converts a Scala mutable `Map` to a Java `Map`.
+ * See [[mutableMapAsJavaMap]].
*/
implicit def mutableMapAsJavaMapConverter[A, B](m : mutable.Map[A, B]): AsJava[ju.Map[A, B]] =
new AsJava(mutableMapAsJavaMap(m))
/**
- * Adds an `asJavaDictionary` method that implicitly converts a Scala
- * mutable `Map` to a Java `Dictionary`.
- *
- * The returned Java `Dictionary` is backed by the provided Scala
- * `Dictionary` and any side-effects of using it via the Java interface
- * will be visible via the Scala interface and vice versa.
- *
- * If the Scala `Dictionary` was previously obtained from an implicit or
- * explicit call of `asMap(java.util.Dictionary)` then the original
- * Java `Dictionary` will be returned.
- *
- * @param m The `Map` to be converted.
- * @return An object with an `asJavaDictionary` method that returns a
- * Java `Dictionary` view of the argument.
+ * Adds an `asJavaDictionary` method that implicitly converts a Scala mutable `Map` to a Java
+ * `Dictionary`. See [[asJavaDictionary]].
*/
implicit def asJavaDictionaryConverter[A, B](m : mutable.Map[A, B]): AsJavaDictionary[A, B] =
new AsJavaDictionary(m)
/**
- * Adds an `asJava` method that implicitly converts a Scala `Map` to
- * a Java `Map`.
- *
- * The returned Java `Map` is backed by the provided Scala `Map` and any
- * side-effects of using it via the Java interface will be visible via
- * the Scala interface and vice versa.
- *
- * If the Scala `Map` was previously obtained from an implicit or explicit
- * call of `asMap(java.util.Map)` then the original Java `Map` will be
- * returned.
- *
- * @param m The `Map` to be converted.
- * @return An object with an `asJava` method that returns a Java `Map` view
- * of the argument.
+ * Adds an `asJava` method that implicitly converts a Scala `Map` to a Java `Map`.
+ * See [[mapAsJavaMap]].
*/
implicit def mapAsJavaMapConverter[A, B](m : Map[A, B]): AsJava[ju.Map[A, B]] =
new AsJava(mapAsJavaMap(m))
/**
- * Adds an `asJava` method that implicitly converts a Scala mutable
- * `concurrent.Map` to a Java `ConcurrentMap`.
- *
- * The returned Java `ConcurrentMap` is backed by the provided Scala
- * `concurrent.Map` and any side-effects of using it via the Java interface
- * will be visible via the Scala interface and vice versa.
- *
- * If the Scala `concurrent.Map` was previously obtained from an implicit or
- * explicit call of `asConcurrentMap(java.util.concurrent.ConcurrentMap)`
- * then the original Java `ConcurrentMap` will be returned.
- *
- * @param m The Scala `concurrent.Map` to be converted.
- * @return An object with an `asJava` method that returns a Java
- * `ConcurrentMap` view of the argument.
+ * Adds an `asJava` method that implicitly converts a Scala mutable `concurrent.Map` to a Java
+ * `ConcurrentMap`. See [[mapAsJavaConcurrentMap]].
*/
implicit def mapAsJavaConcurrentMapConverter[A, B](m: concurrent.Map[A, B]): AsJava[juc.ConcurrentMap[A, B]] =
new AsJava(mapAsJavaConcurrentMap(m))
diff --git a/src/library/scala/collection/convert/DecorateAsScala.scala b/src/library/scala/collection/convert/DecorateAsScala.scala
index 5448f5f91c..b74a06ece5 100644
--- a/src/library/scala/collection/convert/DecorateAsScala.scala
+++ b/src/library/scala/collection/convert/DecorateAsScala.scala
@@ -1,6 +1,6 @@
/* __ *\
** ________ ___ / / ___ Scala API **
-** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
+** / __/ __// _ | / / / _ | (c) 2006-2016, LAMP/EPFL **
** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ **
** /____/\___/_/ |_/____/_/ | | **
** |/ **
@@ -12,185 +12,76 @@ package convert
import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc }
import Decorators._
-import WrapAsScala._
import scala.language.implicitConversions
-trait DecorateAsScala {
+/** Defines `asScala` extension methods for [[JavaConverters]]. */
+trait DecorateAsScala extends AsScalaConverters {
/**
- * Adds an `asScala` method that implicitly converts a Java `Iterator` to
- * a Scala `Iterator`.
- *
- * The returned Scala `Iterator` is backed by the provided Java `Iterator`
- * and any side-effects of using it via the Scala interface will be visible
- * via the Java interface and vice versa.
- *
- * If the Java `Iterator` was previously obtained from an implicit or
- * explicit call of `asIterator(scala.collection.Iterator)` then the
- * original Scala `Iterator` will be returned.
- *
- * @param i The `Iterator` to be converted.
- * @return An object with an `asScala` method that returns a Scala
- * `Iterator` view of the argument.
+ * Adds an `asScala` method that implicitly converts a Java `Iterator` to a Scala `Iterator`.
+ * See [[asScalaIterator]].
*/
implicit def asScalaIteratorConverter[A](i : ju.Iterator[A]): AsScala[Iterator[A]] =
new AsScala(asScalaIterator(i))
/**
- * Adds an `asScala` method that implicitly converts a Java `Enumeration`
- * to a Scala `Iterator`.
- *
- * The returned Scala `Iterator` is backed by the provided Java
- * `Enumeration` and any side-effects of using it via the Scala interface
- * will be visible via the Java interface and vice versa.
- *
- * If the Java `Enumeration` was previously obtained from an implicit or
- * explicit call of `asEnumeration(scala.collection.Iterator)` then the
- * original Scala `Iterator` will be returned.
- *
- * @param i The `Enumeration` to be converted.
- * @return An object with an `asScala` method that returns a Scala
- * `Iterator` view of the argument.
+ * Adds an `asScala` method that implicitly converts a Java `Enumeration` to a Scala `Iterator`.
+ * See [[enumerationAsScalaIterator]].
*/
implicit def enumerationAsScalaIteratorConverter[A](i : ju.Enumeration[A]): AsScala[Iterator[A]] =
new AsScala(enumerationAsScalaIterator(i))
/**
- * Adds an `asScala` method that implicitly converts a Java `Iterable` to
- * a Scala `Iterable`.
- *
- * The returned Scala `Iterable` is backed by the provided Java `Iterable`
- * and any side-effects of using it via the Scala interface will be visible
- * via the Java interface and vice versa.
- *
- * If the Java `Iterable` was previously obtained from an implicit or
- * explicit call of `asIterable(scala.collection.Iterable)` then the original
- * Scala `Iterable` will be returned.
- *
- * @param i The `Iterable` to be converted.
- * @return An object with an `asScala` method that returns a Scala `Iterable`
- * view of the argument.
+ * Adds an `asScala` method that implicitly converts a Java `Iterable` to a Scala `Iterable`.
+ * See [[iterableAsScalaIterable]].
*/
implicit def iterableAsScalaIterableConverter[A](i : jl.Iterable[A]): AsScala[Iterable[A]] =
new AsScala(iterableAsScalaIterable(i))
/**
- * Adds an `asScala` method that implicitly converts a Java `Collection` to
- * an Scala `Iterable`.
- *
- * If the Java `Collection` was previously obtained from an implicit or
- * explicit call of `asCollection(scala.collection.SizedIterable)` then
- * the original Scala `SizedIterable` will be returned.
- *
- * @param i The `Collection` to be converted.
- * @return An object with an `asScala` method that returns a Scala
- * `SizedIterable` view of the argument.
+ * Adds an `asScala` method that implicitly converts a Java `Collection` to an Scala `Iterable`.
+ * See [[collectionAsScalaIterable]].
*/
implicit def collectionAsScalaIterableConverter[A](i : ju.Collection[A]): AsScala[Iterable[A]] =
new AsScala(collectionAsScalaIterable(i))
/**
- * Adds an `asScala` method that implicitly converts a Java `List` to a
- * Scala mutable `Buffer`.
- *
- * The returned Scala `Buffer` is backed by the provided Java `List` and
- * any side-effects of using it via the Scala interface will be visible via
- * the Java interface and vice versa.
- *
- * If the Java `List` was previously obtained from an implicit or explicit
- * call of `asList(scala.collection.mutable.Buffer)` then the original
- * Scala `Buffer` will be returned.
- *
- * @param l The `List` to be converted.
- * @return An object with an `asScala` method that returns a Scala mutable
- * `Buffer` view of the argument.
+ * Adds an `asScala` method that implicitly converts a Java `List` to a Scala mutable `Buffer`.
+ * See [[asScalaBuffer]].
*/
implicit def asScalaBufferConverter[A](l : ju.List[A]): AsScala[mutable.Buffer[A]] =
new AsScala(asScalaBuffer(l))
/**
- * Adds an `asScala` method that implicitly converts a Java `Set` to a
- * Scala mutable `Set`.
- *
- * The returned Scala `Set` is backed by the provided Java `Set` and any
- * side-effects of using it via the Scala interface will be visible via
- * the Java interface and vice versa.
- *
- * If the Java `Set` was previously obtained from an implicit or explicit
- * call of `asSet(scala.collection.mutable.Set)` then the original
- * Scala `Set` will be returned.
- *
- * @param s The `Set` to be converted.
- * @return An object with an `asScala` method that returns a Scala mutable
- * `Set` view of the argument.
+ * Adds an `asScala` method that implicitly converts a Java `Set` to a Scala mutable `Set`.
+ * See [[asScalaSet]].
*/
implicit def asScalaSetConverter[A](s : ju.Set[A]): AsScala[mutable.Set[A]] =
new AsScala(asScalaSet(s))
/**
- * Adds an `asScala` method that implicitly converts a Java `Map` to a Scala
- * mutable `Map`. The returned Scala `Map` is backed by the provided Java
- * `Map` and any side-effects of using it via the Scala interface will
- * be visible via the Java interface and vice versa.
- *
- * If the Java `Map` was previously obtained from an implicit or explicit
- * call of `asMap(scala.collection.mutable.Map)` then the original
- * Scala `Map` will be returned.
- *
- * If the wrapped map is synchronized (e.g. from `java.util.Collections.synchronizedMap`),
- * it is your responsibility to wrap all
- * non-atomic operations with `underlying.synchronized`.
- * This includes `get`, as `java.util.Map`'s API does not allow for an
- * atomic `get` when `null` values may be present.
- *
- * @param m The `Map` to be converted.
- * @return An object with an `asScala` method that returns a Scala mutable
- * `Map` view of the argument.
+ * Adds an `asScala` method that implicitly converts a Java `Map` to a Scala mutable `Map`.
+ * See [[mapAsScalaMap]].
*/
implicit def mapAsScalaMapConverter[A, B](m : ju.Map[A, B]): AsScala[mutable.Map[A, B]] =
new AsScala(mapAsScalaMap(m))
/**
- * Adds an `asScala` method that implicitly converts a Java `ConcurrentMap`
- * to a Scala mutable `concurrent.Map`. The returned Scala `concurrent.Map` is
- * backed by the provided Java `ConcurrentMap` and any side-effects of using
- * it via the Scala interface will be visible via the Java interface and
- * vice versa.
- *
- * If the Java `ConcurrentMap` was previously obtained from an implicit or
- * explicit call of `mapAsScalaConcurrentMap(scala.collection.mutable.ConcurrentMap)`
- * then the original Scala `concurrent.Map` will be returned.
- *
- * @param m The `ConcurrentMap` to be converted.
- * @return An object with an `asScala` method that returns a Scala mutable
- * `concurrent.Map` view of the argument.
+ * Adds an `asScala` method that implicitly converts a Java `ConcurrentMap` to a Scala mutable
+ * `concurrent.Map`. See [[mapAsScalaConcurrentMap]].
*/
implicit def mapAsScalaConcurrentMapConverter[A, B](m: juc.ConcurrentMap[A, B]): AsScala[concurrent.Map[A, B]] =
new AsScala(mapAsScalaConcurrentMap(m))
/**
- * Adds an `asScala` method that implicitly converts a Java `Dictionary`
- * to a Scala mutable `Map[String, String]`. The returned Scala
- * `Map[String, String]` is backed by the provided Java `Dictionary` and
- * any side-effects of using it via the Scala interface will be visible via
- * the Java interface and vice versa.
- *
- * @param p The `Dictionary` to be converted.
- * @return An object with an `asScala` method that returns a Scala mutable
- * `Map[String, String]` view of the argument.
+ * Adds an `asScala` method that implicitly converts a Java `Dictionary` to a Scala mutable `Map`.
+ * See [[dictionaryAsScalaMap]].
*/
implicit def dictionaryAsScalaMapConverter[A, B](p: ju.Dictionary[A, B]): AsScala[mutable.Map[A, B]] =
new AsScala(dictionaryAsScalaMap(p))
/**
- * Adds an `asScala` method that implicitly converts a Java `Properties`
- * to a Scala mutable `Map[String, String]`. The returned Scala
- * `Map[String, String]` is backed by the provided Java `Properties` and
- * any side-effects of using it via the Scala interface will be visible via
- * the Java interface and vice versa.
- *
- * @param p The `Properties` to be converted.
- * @return An object with an `asScala` method that returns a Scala mutable
- * `Map[String, String]` view of the argument.
+ * Adds an `asScala` method that implicitly converts a Java `Properties` to a Scala mutable
+ * `Map[String, String]`. See [[propertiesAsScalaMap]].
*/
implicit def propertiesAsScalaMapConverter(p: ju.Properties): AsScala[mutable.Map[String, String]] =
new AsScala(propertiesAsScalaMap(p))
diff --git a/src/library/scala/collection/convert/Decorators.scala b/src/library/scala/collection/convert/Decorators.scala
index d232fa04e1..3e45a02254 100644
--- a/src/library/scala/collection/convert/Decorators.scala
+++ b/src/library/scala/collection/convert/Decorators.scala
@@ -12,7 +12,7 @@ package convert
import java.{ util => ju }
-private[collection] trait Decorators {
+private[collection] object Decorators {
/** Generic class containing the `asJava` converter method */
class AsJava[A](op: => A) {
/** Converts a Scala collection to the corresponding Java collection */
@@ -28,20 +28,18 @@ private[collection] trait Decorators {
/** Generic class containing the `asJavaCollection` converter method */
class AsJavaCollection[A](i: Iterable[A]) {
/** Converts a Scala `Iterable` to a Java `Collection` */
- def asJavaCollection: ju.Collection[A] = JavaConversions.asJavaCollection(i)
+ def asJavaCollection: ju.Collection[A] = JavaConverters.asJavaCollection(i)
}
/** Generic class containing the `asJavaEnumeration` converter method */
class AsJavaEnumeration[A](i: Iterator[A]) {
/** Converts a Scala `Iterator` to a Java `Enumeration` */
- def asJavaEnumeration: ju.Enumeration[A] = JavaConversions.asJavaEnumeration(i)
+ def asJavaEnumeration: ju.Enumeration[A] = JavaConverters.asJavaEnumeration(i)
}
/** Generic class containing the `asJavaDictionary` converter method */
class AsJavaDictionary[A, B](m : mutable.Map[A, B]) {
/** Converts a Scala `Map` to a Java `Dictionary` */
- def asJavaDictionary: ju.Dictionary[A, B] = JavaConversions.asJavaDictionary(m)
+ def asJavaDictionary: ju.Dictionary[A, B] = JavaConverters.asJavaDictionary(m)
}
}
-
-private[collection] object Decorators extends Decorators
diff --git a/src/library/scala/collection/convert/ImplicitConversions.scala b/src/library/scala/collection/convert/ImplicitConversions.scala
new file mode 100644
index 0000000000..747e0606c8
--- /dev/null
+++ b/src/library/scala/collection/convert/ImplicitConversions.scala
@@ -0,0 +1,125 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2016, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+package collection
+package convert
+
+import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc }
+import scala.language.implicitConversions
+
+import JavaConverters._
+
+/** Defines implicit converter methods from Java to Scala collections. */
+trait ToScalaImplicits {
+ /** Implicitly converts a Java `Iterator` to a Scala `Iterator`. See [[asScalaIterator]]. */
+ implicit def `iterator asScala`[A](it: ju.Iterator[A]): Iterator[A] = asScalaIterator(it)
+
+ /** Implicitly converts a Java `Enumeration` to a Scala `Iterator`. See [[enumerationAsScalaIterator]]. */
+ implicit def `enumeration AsScalaIterator`[A](i: ju.Enumeration[A]): Iterator[A] = enumerationAsScalaIterator(i)
+
+ /** Implicitly converts a Java `Iterable` to a Scala `Iterable`. See [[iterableAsScalaIterable]]. */
+ implicit def `iterable AsScalaIterable`[A](i: jl.Iterable[A]): Iterable[A] = iterableAsScalaIterable(i)
+
+ /** Implicitly converts a Java `Collection` to an Scala `Iterable`. See [[collectionAsScalaIterable]]. */
+ implicit def `collection AsScalaIterable`[A](i: ju.Collection[A]): Iterable[A] = collectionAsScalaIterable(i)
+
+ /** Implicitly converts a Java `List` to a Scala mutable `Buffer`. See [[asScalaBuffer]]. */
+ implicit def `list asScalaBuffer`[A](l: ju.List[A]): mutable.Buffer[A] = asScalaBuffer(l)
+
+ /** Implicitly converts a Java `Set` to a Scala mutable `Set`. See [[asScalaSet]]. */
+ implicit def `set asScala`[A](s: ju.Set[A]): mutable.Set[A] = asScalaSet(s)
+
+ /** Implicitly converts a Java `Map` to a Scala mutable `Map`. See [[mapAsScalaMap]]. */
+ implicit def `map AsScala`[A, B](m: ju.Map[A, B]): mutable.Map[A, B] = mapAsScalaMap(m)
+
+ /** Implicitly converts a Java `ConcurrentMap` to a Scala mutable `ConcurrentMap`. See [[mapAsScalaConcurrentMap]]. */
+ implicit def `map AsScalaConcurrentMap`[A, B](m: juc.ConcurrentMap[A, B]): concurrent.Map[A, B] = mapAsScalaConcurrentMap(m)
+
+ /** Implicitly converts a Java `Dictionary` to a Scala mutable `Map`. See [[dictionaryAsScalaMap]]. */
+ implicit def `dictionary AsScalaMap`[A, B](p: ju.Dictionary[A, B]): mutable.Map[A, B] = dictionaryAsScalaMap(p)
+
+ /** Implicitly converts a Java `Properties` to a Scala `mutable Map[String, String]`. See [[propertiesAsScalaMap]]. */
+ implicit def `properties AsScalaMap`(p: ju.Properties): mutable.Map[String, String] = propertiesAsScalaMap(p)
+}
+
+/** Defines implicit conversions from Scala to Java collections. */
+trait ToJavaImplicits {
+ /** Implicitly converts a Scala `Iterator` to a Java `Iterator`. See [[asJavaIterator]]. */
+ implicit def `iterator asJava`[A](it: Iterator[A]): ju.Iterator[A] = asJavaIterator(it)
+
+ /** Implicitly converts a Scala `Iterator` to a Java `Enumeration`. See [[asJavaEnumeration]]. */
+ implicit def `enumeration asJava`[A](it: Iterator[A]): ju.Enumeration[A] = asJavaEnumeration(it)
+
+ /** Implicitly converts a Scala `Iterable` to a Java `Iterable`. See [[asJavaIterable]]. */
+ implicit def `iterable asJava`[A](i: Iterable[A]): jl.Iterable[A] = asJavaIterable(i)
+
+ /** Implicitly converts a Scala `Iterable` to an immutable Java `Collection`. See [[asJavaCollection]]. */
+ implicit def `collection asJava`[A](it: Iterable[A]): ju.Collection[A] = asJavaCollection(it)
+
+ /** Implicitly converts a Scala mutable `Buffer` to a Java `List`. See [[bufferAsJavaList]]. */
+ implicit def `buffer AsJavaList`[A](b: mutable.Buffer[A]): ju.List[A] = bufferAsJavaList(b)
+
+ /** Implicitly converts a Scala mutable `Seq` to a Java `List`. See [[mutableSeqAsJavaList]]. */
+ implicit def `mutableSeq AsJavaList`[A](seq: mutable.Seq[A]): ju.List[A] = mutableSeqAsJavaList(seq)
+
+ /** Implicitly converts a Scala `Seq` to a Java `List`. See [[seqAsJavaList]]. */
+ implicit def `seq AsJavaList`[A](seq: Seq[A]): ju.List[A] = seqAsJavaList(seq)
+
+ /** Implicitly converts a Scala mutable `Set` to a Java `Set`. See [[mutableSetAsJavaSet]]. */
+ implicit def `mutableSet AsJavaSet`[A](s: mutable.Set[A]): ju.Set[A] = mutableSetAsJavaSet(s)
+
+ /** Implicitly converts a Scala `Set` to a Java `Set`. See [[setAsJavaSet]]. */
+ implicit def `set AsJavaSet`[A](s: Set[A]): ju.Set[A] = setAsJavaSet(s)
+
+ /** Implicitly converts a Scala mutable `Map` to a Java `Map`. See [[mutableMapAsJavaMap]]. */
+ implicit def `mutableMap AsJavaMap`[A, B](m: mutable.Map[A, B]): ju.Map[A, B] = mutableMapAsJavaMap(m)
+
+ /** Implicitly converts a Scala mutable `Map` to a Java `Dictionary`. See [[asJavaDictionary]]. */
+ implicit def `dictionary asJava`[A, B](m: mutable.Map[A, B]): ju.Dictionary[A, B] = asJavaDictionary(m)
+
+ /** Implicitly converts a Scala `Map` to a Java `Map`. See [[mapAsJavaMap]]. */
+ implicit def `map AsJavaMap`[A, B](m: Map[A, B]): ju.Map[A, B] = mapAsJavaMap(m)
+
+ /** Implicitly converts a Scala mutable `concurrent.Map` to a Java `ConcurrentMap`. See [[mapAsJavaConcurrentMap]]. */
+ implicit def `map AsJavaConcurrentMap`[A, B](m: concurrent.Map[A, B]): juc.ConcurrentMap[A, B] = mapAsJavaConcurrentMap(m)
+}
+
+/**
+ * Convenience for miscellaneous implicit conversions from Scala to Java collections API.
+ *
+ * It is recommended to use explicit conversions provided by [[collection.JavaConverters]] instead.
+ * Implicit conversions may cause unexpected issues, see [[ImplicitConversions]].
+ */
+object ImplicitConversionsToJava extends ToJavaImplicits
+
+/**
+ * Convenience for miscellaneous implicit conversions from Java to Scala collections API.
+ *
+ * It is recommended to use explicit conversions provided by [[collection.JavaConverters]] instead.
+ * Implicit conversions may cause unexpected issues, see [[ImplicitConversions]].
+ */
+object ImplicitConversionsToScala extends ToScalaImplicits
+
+/**
+ * Convenience for miscellaneous implicit conversions between Java and Scala collections API.
+ *
+ * It is recommended to use explicit conversions provided by [[collection.JavaConverters]] instead.
+ * Implicit conversions may cause unexpected issues. Example:
+ *
+ * {{{
+ * import collection.convert.ImplicitConversions._
+ * case class StringBox(s: String)
+ * val m = Map(StringBox("one") -> "uno")
+ * m.get("one")
+ * }}}
+ *
+ * The above example returns `null` instead of producing a type error at compile-time. The map is
+ * implicitly converted to a `java.util.Map` which provides a method `get(x: AnyRef)`.
+ */
+object ImplicitConversions extends ToScalaImplicits with ToJavaImplicits
diff --git a/src/library/scala/collection/convert/WrapAsJava.scala b/src/library/scala/collection/convert/WrapAsJava.scala
index e97a2ff1fc..e45c1666a5 100644
--- a/src/library/scala/collection/convert/WrapAsJava.scala
+++ b/src/library/scala/collection/convert/WrapAsJava.scala
@@ -13,7 +13,27 @@ package convert
import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc }
import scala.language.implicitConversions
-trait WrapAsJava {
+@deprecated("Use JavaConverters or consider ToJavaImplicits", since="2.12")
+trait WrapAsJava extends LowPriorityWrapAsJava {
+ // provide higher-priority implicits with names that don't exist in JavaConverters for the case
+ // when importing both JavaConverters._ and JavaConversions._. otherwise implicit conversions
+ // would not apply, see https://github.com/scala/scala/pull/5109#issuecomment-212417789
+ implicit def `deprecated asJavaIterator`[A](it: Iterator[A]): ju.Iterator[A] = asJavaIterator(it)
+ implicit def `deprecated asJavaEnumeration`[A](it: Iterator[A]): ju.Enumeration[A] = asJavaEnumeration(it)
+ implicit def `deprecated asJavaIterable`[A](i: Iterable[A]): jl.Iterable[A] = asJavaIterable(i)
+ implicit def `deprecated asJavaCollection`[A](it: Iterable[A]): ju.Collection[A] = asJavaCollection(it)
+ implicit def `deprecated bufferAsJavaList`[A](b: mutable.Buffer[A]): ju.List[A] = bufferAsJavaList(b)
+ implicit def `deprecated mutableSeqAsJavaList`[A](seq: mutable.Seq[A]): ju.List[A] = mutableSeqAsJavaList(seq)
+ implicit def `deprecated seqAsJavaList`[A](seq: Seq[A]): ju.List[A] = seqAsJavaList(seq)
+ implicit def `deprecated mutableSetAsJavaSet`[A](s: mutable.Set[A]): ju.Set[A] = mutableSetAsJavaSet(s)
+ implicit def `deprecated setAsJavaSet`[A](s: Set[A]): ju.Set[A] = setAsJavaSet(s)
+ implicit def `deprecated mutableMapAsJavaMap`[A, B](m: mutable.Map[A, B]): ju.Map[A, B] = mutableMapAsJavaMap(m)
+ implicit def `deprecated asJavaDictionary`[A, B](m: mutable.Map[A, B]): ju.Dictionary[A, B] = asJavaDictionary(m)
+ implicit def `deprecated mapAsJavaMap`[A, B](m: Map[A, B]): ju.Map[A, B] = mapAsJavaMap(m)
+ implicit def `deprecated mapAsJavaConcurrentMap`[A, B](m: concurrent.Map[A, B]): juc.ConcurrentMap[A, B] = mapAsJavaConcurrentMap(m)
+}
+
+private[convert] trait LowPriorityWrapAsJava {
import Wrappers._
/**
@@ -266,4 +286,5 @@ trait WrapAsJava {
}
}
-object WrapAsJava extends WrapAsJava { }
+@deprecated("Use JavaConverters or consider ImplicitConversionsToJava", since="2.12")
+object WrapAsJava extends WrapAsJava
diff --git a/src/library/scala/collection/convert/WrapAsScala.scala b/src/library/scala/collection/convert/WrapAsScala.scala
index ee161dcc87..514490e348 100644
--- a/src/library/scala/collection/convert/WrapAsScala.scala
+++ b/src/library/scala/collection/convert/WrapAsScala.scala
@@ -13,8 +13,26 @@ package convert
import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc }
import scala.language.implicitConversions
-trait WrapAsScala {
+@deprecated("Use JavaConverters or consider ToScalaImplicits", since="2.12")
+trait WrapAsScala extends LowPriorityWrapAsScala {
+ // provide higher-priority implicits with names that don't exist in JavaConverters for the case
+ // when importing both JavaConverters._ and JavaConversions._. otherwise implicit conversions
+ // would not apply, see https://github.com/scala/scala/pull/5109#issuecomment-212417789
+ implicit def `deprecated asScalaIterator`[A](it: ju.Iterator[A]): Iterator[A] = asScalaIterator(it)
+ implicit def `deprecated enumerationAsScalaIterator`[A](i: ju.Enumeration[A]): Iterator[A] = enumerationAsScalaIterator(i)
+ implicit def `deprecated iterableAsScalaIterable`[A](i: jl.Iterable[A]): Iterable[A] = iterableAsScalaIterable(i)
+ implicit def `deprecated collectionAsScalaIterable`[A](i: ju.Collection[A]): Iterable[A] = collectionAsScalaIterable(i)
+ implicit def `deprecated asScalaBuffer`[A](l: ju.List[A]): mutable.Buffer[A] = asScalaBuffer(l)
+ implicit def `deprecated asScalaSet`[A](s: ju.Set[A]): mutable.Set[A] = asScalaSet(s)
+ implicit def `deprecated mapAsScalaMap`[A, B](m: ju.Map[A, B]): mutable.Map[A, B] = mapAsScalaMap(m)
+ implicit def `deprecated mapAsScalaConcurrentMap`[A, B](m: juc.ConcurrentMap[A, B]): concurrent.Map[A, B] = mapAsScalaConcurrentMap(m)
+ implicit def `deprecated dictionaryAsScalaMap`[A, B](p: ju.Dictionary[A, B]): mutable.Map[A, B] = dictionaryAsScalaMap(p)
+ implicit def `deprecated propertiesAsScalaMap`(p: ju.Properties): mutable.Map[String, String] = propertiesAsScalaMap(p)
+}
+
+private[convert] trait LowPriorityWrapAsScala {
import Wrappers._
+
/**
* Implicitly converts a Java `Iterator` to a Scala `Iterator`.
*
@@ -207,4 +225,5 @@ trait WrapAsScala {
}
}
-object WrapAsScala extends WrapAsScala { }
+@deprecated("Use JavaConverters or consider ImplicitConversionsToScala", since="2.12")
+object WrapAsScala extends WrapAsScala
diff --git a/src/library/scala/collection/convert/Wrappers.scala b/src/library/scala/collection/convert/Wrappers.scala
index 3edc5ba1b4..6d745bc6b0 100644
--- a/src/library/scala/collection/convert/Wrappers.scala
+++ b/src/library/scala/collection/convert/Wrappers.scala
@@ -14,10 +14,7 @@ import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc }
import WrapAsScala._
import WrapAsJava._
-/** Don't put the implementations in the same scope as the implicits
- * which utilize them, or they will stow away into every scope which
- * extends one of those implementations. See SI-5580.
- */
+/** Adapters for Java/Scala collections API. */
private[collection] trait Wrappers {
trait IterableWrapperTrait[A] extends ju.AbstractCollection[A] {
val underlying: Iterable[A]
diff --git a/src/library/scala/collection/convert/package.scala b/src/library/scala/collection/convert/package.scala
index 13970f9a3e..7f48023b58 100644
--- a/src/library/scala/collection/convert/package.scala
+++ b/src/library/scala/collection/convert/package.scala
@@ -10,10 +10,17 @@ package scala
package collection
package object convert {
+ @deprecated("Use JavaConverters", since="2.12")
val decorateAsJava = new DecorateAsJava { }
+ @deprecated("Use JavaConverters", since="2.12")
val decorateAsScala = new DecorateAsScala { }
- val decorateAll = new DecorateAsJava with DecorateAsScala { }
+ @deprecated("Use JavaConverters", since="2.12")
+ val decorateAll = JavaConverters
+
+ @deprecated("Use JavaConverters or consider ImplicitConversionsToJava", since="2.12")
val wrapAsJava = new WrapAsJava { }
+ @deprecated("Use JavaConverters or consider ImplicitConversionsToScala", since="2.12")
val wrapAsScala = new WrapAsScala { }
+ @deprecated("Use JavaConverters or consider ImplicitConversions", since="2.12")
val wrapAll = new WrapAsJava with WrapAsScala { }
}
diff --git a/src/library/scala/collection/immutable/BitSet.scala b/src/library/scala/collection/immutable/BitSet.scala
index 6bb1f116fe..ecf3326c7f 100644
--- a/src/library/scala/collection/immutable/BitSet.scala
+++ b/src/library/scala/collection/immutable/BitSet.scala
@@ -68,6 +68,8 @@ object BitSet extends BitSetFactory[BitSet] {
/** The empty bitset */
val empty: BitSet = new BitSet1(0L)
+ private def createSmall(a: Long, b: Long): BitSet = if (b == 0L) new BitSet1(a) else new BitSet2(a, b)
+
/** A builder that takes advantage of mutable BitSets. */
def newBuilder: Builder[Int, BitSet] = new Builder[Int, BitSet] {
private[this] val b = new mutable.BitSet
@@ -84,7 +86,7 @@ object BitSet extends BitSetFactory[BitSet] {
val len = elems.length
if (len == 0) empty
else if (len == 1) new BitSet1(elems(0))
- else if (len == 2) new BitSet2(elems(0), elems(1))
+ else if (len == 2) createSmall(elems(0), elems(1))
else {
val a = new Array[Long](len)
Array.copy(elems, 0, a, 0, len)
@@ -99,7 +101,7 @@ object BitSet extends BitSetFactory[BitSet] {
val len = elems.length
if (len == 0) empty
else if (len == 1) new BitSet1(elems(0))
- else if (len == 2) new BitSet2(elems(0), elems(1))
+ else if (len == 2) createSmall(elems(0), elems(1))
else new BitSetN(elems)
}
@@ -109,7 +111,7 @@ object BitSet extends BitSetFactory[BitSet] {
protected def word(idx: Int) = if (idx == 0) elems else 0L
protected def updateWord(idx: Int, w: Long): BitSet =
if (idx == 0) new BitSet1(w)
- else if (idx == 1) new BitSet2(elems, w)
+ else if (idx == 1) createSmall(elems, w)
else fromBitMaskNoCopy(updateArray(Array(elems), idx, w))
override def head: Int =
if (elems == 0L) throw new NoSuchElementException("Empty BitSet")
@@ -124,7 +126,7 @@ object BitSet extends BitSetFactory[BitSet] {
protected def word(idx: Int) = if (idx == 0) elems0 else if (idx == 1) elems1 else 0L
protected def updateWord(idx: Int, w: Long): BitSet =
if (idx == 0) new BitSet2(w, elems1)
- else if (idx == 1) new BitSet2(elems0, w)
+ else if (idx == 1) createSmall(elems0, w)
else fromBitMaskNoCopy(updateArray(Array(elems0, elems1), idx, w))
override def head: Int =
if (elems0 == 0L) {
@@ -135,7 +137,7 @@ object BitSet extends BitSetFactory[BitSet] {
override def tail: BitSet =
if (elems0 == 0L) {
if (elems1 == 0L) throw new NoSuchElementException("Empty BitSet")
- new BitSet2(elems0, elems1 - java.lang.Long.lowestOneBit(elems1))
+ createSmall(elems0, elems1 - java.lang.Long.lowestOneBit(elems1))
}
else new BitSet2(elems0 - java.lang.Long.lowestOneBit(elems0), elems1)
}
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/collection/mutable/ArrayOps.scala b/src/library/scala/collection/mutable/ArrayOps.scala
index b7682c5ab9..507585b9cf 100644
--- a/src/library/scala/collection/mutable/ArrayOps.scala
+++ b/src/library/scala/collection/mutable/ArrayOps.scala
@@ -11,7 +11,6 @@ package collection
package mutable
import scala.reflect.ClassTag
-import scala.runtime.ScalaRunTime._
import parallel.mutable.ParArray
/** This class serves as a wrapper for `Array`s with all the operations found in
@@ -35,7 +34,7 @@ import parallel.mutable.ParArray
sealed trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParallelizable[T, ParArray[T]] {
private def elementClass: Class[_] =
- arrayElementClass(repr.getClass)
+ repr.getClass.getComponentType
override def copyToArray[U >: T](xs: Array[U], start: Int, len: Int) {
val l = len min repr.length min (xs.length - start)
@@ -43,7 +42,7 @@ sealed trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomPara
}
override def toArray[U >: T : ClassTag]: Array[U] = {
- val thatElementClass = arrayElementClass(implicitly[ClassTag[U]])
+ val thatElementClass = implicitly[ClassTag[U]].runtimeClass
if (elementClass eq thatElementClass)
repr.asInstanceOf[Array[U]]
else
@@ -91,7 +90,7 @@ sealed trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomPara
val bb: Builder[Array[U], Array[Array[U]]] = Array.newBuilder(ClassTag[Array[U]](elementClass))
if (isEmpty) bb.result()
else {
- def mkRowBuilder() = Array.newBuilder(ClassTag[U](arrayElementClass(elementClass)))
+ def mkRowBuilder() = Array.newBuilder(ClassTag[U](elementClass.getComponentType))
val bs = asArray(head) map (_ => mkRowBuilder())
for (xs <- this) {
var i = 0
@@ -184,7 +183,7 @@ object ArrayOps {
override protected[this] def thisCollection: WrappedArray[T] = new WrappedArray.ofRef[T](repr)
override protected[this] def toCollection(repr: Array[T]): WrappedArray[T] = new WrappedArray.ofRef[T](repr)
- override protected[this] def newBuilder = new ArrayBuilder.ofRef[T]()(ClassTag[T](arrayElementClass(repr.getClass)))
+ override protected[this] def newBuilder = new ArrayBuilder.ofRef[T]()(ClassTag[T](repr.getClass.getComponentType))
def length: Int = repr.length
def apply(index: Int): T = repr(index)
diff --git a/src/library/scala/collection/mutable/PriorityQueue.scala b/src/library/scala/collection/mutable/PriorityQueue.scala
index b4112c03dd..a6c0fc2077 100644
--- a/src/library/scala/collection/mutable/PriorityQueue.scala
+++ b/src/library/scala/collection/mutable/PriorityQueue.scala
@@ -66,7 +66,7 @@ sealed class PriorityQueue[A](implicit val ord: Ordering[A])
def p_swap(a: Int, b: Int) = super.swap(a, b)
}
- protected[this] override def newBuilder = new PriorityQueue[A]
+ protected[this] override def newBuilder = PriorityQueue.newBuilder[A]
private val resarr = new ResizableArrayAccess[A]
@@ -89,14 +89,15 @@ sealed class PriorityQueue[A](implicit val ord: Ordering[A])
}
}
- protected def fixDown(as: Array[AnyRef], m: Int, n: Int): Unit = {
+ protected def fixDown(as: Array[AnyRef], m: Int, n: Int): Boolean = {
+ // returns true if any swaps were done (used in heapify)
var k: Int = m
while (n >= 2 * k) {
var j = 2 * k
if (j < n && toA(as(j)) < toA(as(j + 1)))
j += 1
if (toA(as(k)) >= toA(as(j)))
- return
+ return k != m
else {
val h = as(k)
as(k) = as(j)
@@ -104,6 +105,7 @@ sealed class PriorityQueue[A](implicit val ord: Ordering[A])
k = j
}
}
+ k != m
}
/** Inserts a single element into the priority queue.
@@ -119,6 +121,66 @@ sealed class PriorityQueue[A](implicit val ord: Ordering[A])
this
}
+ override def ++=(xs: TraversableOnce[A]): this.type = {
+ val from = resarr.p_size0
+ for (x <- xs) unsafeAdd(x)
+ heapify(from)
+ this
+ }
+
+ private def unsafeAdd(elem: A): Unit = {
+ // like += but skips fixUp, which breaks the ordering invariant
+ // a series of unsafeAdds MUST be followed by heapify
+ resarr.p_ensureSize(resarr.p_size0 + 1)
+ resarr.p_array(resarr.p_size0) = elem.asInstanceOf[AnyRef]
+ resarr.p_size0 += 1
+ }
+
+ private def heapify(from: Int): Unit = {
+ // elements at indices 1..from-1 were already in heap order before any adds
+ // elements at indices from..n are newly added, their order must be fixed
+ val n = length
+
+ if (from <= 2) {
+ // no pre-existing order to maintain, do the textbook heapify algorithm
+ for (i <- n/2 to 1 by -1) fixDown(resarr.p_array, i, n)
+ }
+ else if (n - from < 4) {
+ // for very small adds, doing the simplest fix is faster
+ for (i <- from to n) fixUp(resarr.p_array, i)
+ }
+ else {
+ var min = from/2 // tracks the minimum element in the queue
+ val queue = scala.collection.mutable.Queue[Int](min)
+
+ // do fixDown on the parents of all the new elements
+ // except the parent of the first new element, which is in the queue
+ // (that parent is treated specially because it might be the root)
+ for (i <- n/2 until min by -1) {
+ if (fixDown(resarr.p_array, i, n)) {
+ // there was a swap, so also need to fixDown i's parent
+ val parent = i/2
+ if (parent < min) { // make sure same parent isn't added twice
+ min = parent
+ queue += parent
+ }
+ }
+ }
+
+ while (queue.nonEmpty) {
+ val i = queue.dequeue()
+ if (fixDown(resarr.p_array, i, n)) {
+ val parent = i/2
+ if (parent < min && parent > 0) {
+ // the "parent > 0" is to avoid adding the parent of the root
+ min = parent
+ queue += parent
+ }
+ }
+ }
+ }
+ }
+
/** Adds all elements provided by a `TraversableOnce` object
* into the priority queue.
*
@@ -142,9 +204,11 @@ sealed class PriorityQueue[A](implicit val ord: Ordering[A])
def dequeue(): A =
if (resarr.p_size0 > 1) {
resarr.p_size0 = resarr.p_size0 - 1
- resarr.p_swap(1, resarr.p_size0)
+ val result = resarr.p_array(1)
+ resarr.p_array(1) = resarr.p_array(resarr.p_size0)
+ resarr.p_array(resarr.p_size0) = null // erase reference from array
fixDown(resarr.p_array, 1, resarr.p_size0 - 1)
- toA(resarr.p_array(resarr.p_size0))
+ toA(result)
} else
throw new NoSuchElementException("no element to remove from heap")
@@ -186,27 +250,34 @@ sealed class PriorityQueue[A](implicit val ord: Ordering[A])
}
}
- /** Returns the reverse of this queue. The priority queue that gets
- * returned will have an inversed ordering - if for some elements
- * `x` and `y` the original queue's ordering
- * had `compare` returning an integer ''w'', the new one will return ''-w'',
- * assuming the original ordering abides its contract.
+ /** Returns the reverse of this priority queue. The new priority queue has
+ * the same elements as the original, but the opposite ordering.
*
- * Note that the order of the elements will be reversed unless the
- * `compare` method returns 0. In this case, such elements
- * will be subsequent, but their corresponding subinterval may be inappropriately
- * reversed. However, due to the compare-equals contract, they will also be equal.
+ * For example, the element with the highest priority in `pq` has the lowest
+ * priority in `pq.reverse`, and vice versa.
*
- * @return A reversed priority queue.
+ * Ties are handled arbitrarily. Elements with equal priority may or
+ * may not be reversed with respect to each other.
+ *
+ * @return the reversed priority queue.
*/
def reverse = {
- val revq = new PriorityQueue[A]()(new scala.math.Ordering[A] {
- def compare(x: A, y: A) = ord.compare(y, x)
- })
- for (i <- 1 until resarr.length) revq += resarr(i)
+ val revq = new PriorityQueue[A]()(ord.reverse)
+ // copy the existing data into the new array backwards
+ // this won't put it exactly into the correct order,
+ // but will require less fixing than copying it in
+ // the original order
+ val n = resarr.p_size0
+ revq.resarr.p_ensureSize(n)
+ revq.resarr.p_size0 = n
+ val from = resarr.p_array
+ val to = revq.resarr.p_array
+ for (i <- 1 until n) to(i) = from(n-i)
+ revq.heapify(1)
revq
}
+
/** Returns an iterator which yields all the elements in the reverse order
* than that returned by the method `iterator`.
*
@@ -256,12 +327,27 @@ sealed class PriorityQueue[A](implicit val ord: Ordering[A])
*
* @return a priority queue with the same elements.
*/
- override def clone(): PriorityQueue[A] = new PriorityQueue[A] ++= this.iterator
+ override def clone(): PriorityQueue[A] = {
+ val pq = new PriorityQueue[A]
+ val n = resarr.p_size0
+ pq.resarr.p_ensureSize(n)
+ pq.resarr.p_size0 = n
+ scala.compat.Platform.arraycopy(resarr.p_array, 1, pq.resarr.p_array, 1, n-1)
+ pq
+ }
}
object PriorityQueue extends OrderedTraversableFactory[PriorityQueue] {
- def newBuilder[A](implicit ord: Ordering[A]) = new PriorityQueue[A]
+ def newBuilder[A](implicit ord: Ordering[A]): Builder[A, PriorityQueue[A]] = {
+ new Builder[A, PriorityQueue[A]] {
+ val pq = new PriorityQueue[A]
+ def +=(elem: A): this.type = { pq.unsafeAdd(elem); this }
+ def result(): PriorityQueue[A] = { pq.heapify(1); pq }
+ def clear(): Unit = pq.clear()
+ }
+ }
+
implicit def canBuildFrom[A](implicit ord: Ordering[A]): CanBuildFrom[Coll, A, PriorityQueue[A]] = new GenericCanBuildFrom[A]
}
diff --git a/src/library/scala/collection/mutable/WrappedArray.scala b/src/library/scala/collection/mutable/WrappedArray.scala
index 8740bda835..01dcd9bde5 100644
--- a/src/library/scala/collection/mutable/WrappedArray.scala
+++ b/src/library/scala/collection/mutable/WrappedArray.scala
@@ -13,7 +13,6 @@ package collection
package mutable
import scala.reflect.ClassTag
-import scala.runtime.ScalaRunTime._
import scala.collection.generic._
import scala.collection.parallel.mutable.ParArray
@@ -46,7 +45,7 @@ extends AbstractSeq[T]
def elemTag: ClassTag[T]
@deprecated("use elemTag instead", "2.10.0")
- def elemManifest: ClassManifest[T] = ClassManifest.fromClass[T](arrayElementClass(elemTag).asInstanceOf[Class[T]])
+ def elemManifest: ClassManifest[T] = ClassManifest.fromClass[T](elemTag.runtimeClass.asInstanceOf[Class[T]])
/** The length of the array */
def length: Int
@@ -63,10 +62,10 @@ extends AbstractSeq[T]
override def par = ParArray.handoff(array)
private def elementClass: Class[_] =
- arrayElementClass(array.getClass)
+ array.getClass.getComponentType
override def toArray[U >: T : ClassTag]: Array[U] = {
- val thatElementClass = arrayElementClass(implicitly[ClassTag[U]])
+ val thatElementClass = implicitly[ClassTag[U]].runtimeClass
if (elementClass eq thatElementClass)
array.asInstanceOf[Array[U]]
else
@@ -122,7 +121,7 @@ object WrappedArray {
def newBuilder[A]: Builder[A, IndexedSeq[A]] = new ArrayBuffer
final class ofRef[T <: AnyRef](val array: Array[T]) extends WrappedArray[T] with Serializable {
- lazy val elemTag = ClassTag[T](arrayElementClass(array.getClass))
+ lazy val elemTag = ClassTag[T](array.getClass.getComponentType)
def length: Int = array.length
def apply(index: Int): T = array(index).asInstanceOf[T]
def update(index: Int, elem: T) { array(index) = elem }
diff --git a/src/library/scala/collection/mutable/WrappedArrayBuilder.scala b/src/library/scala/collection/mutable/WrappedArrayBuilder.scala
index c4781321d7..5bc5811450 100644
--- a/src/library/scala/collection/mutable/WrappedArrayBuilder.scala
+++ b/src/library/scala/collection/mutable/WrappedArrayBuilder.scala
@@ -13,7 +13,6 @@ package collection
package mutable
import scala.reflect.ClassTag
-import scala.runtime.ScalaRunTime._
/** A builder class for arrays.
*
@@ -34,7 +33,7 @@ class WrappedArrayBuilder[A](tag: ClassTag[A]) extends ReusableBuilder[A, Wrappe
private var size: Int = 0
private def mkArray(size: Int): WrappedArray[A] = {
- val runtimeClass = arrayElementClass(tag)
+ val runtimeClass = tag.runtimeClass
val newelems = runtimeClass match {
case java.lang.Byte.TYPE => new WrappedArray.ofByte(new Array[Byte](size)).asInstanceOf[WrappedArray[A]]
case java.lang.Short.TYPE => new WrappedArray.ofShort(new Array[Short](size)).asInstanceOf[WrappedArray[A]]
diff --git a/src/library/scala/collection/package.scala b/src/library/scala/collection/package.scala
index 856f901b77..6df254c0e0 100644
--- a/src/library/scala/collection/package.scala
+++ b/src/library/scala/collection/package.scala
@@ -76,13 +76,9 @@ package scala
* The concrete parallel collections also have specific performance characteristics which are
* described in [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#performance-characteristics the parallel collections guide]]
*
- * === Converting between Java Collections ===
+ * === Converting to and from Java Collections ===
*
- * The [[scala.collection.JavaConversions]] object provides implicit defs that
- * will allow mostly seamless integration between APIs using Java Collections
- * and the Scala collections library.
- *
- * Alternatively the [[scala.collection.JavaConverters]] object provides a collection
+ * The [[scala.collection.JavaConverters]] object provides a collection
* of decorators that allow converting between Scala and Java collections using `asScala`
* and `asJava` methods.
*/
diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala
index b10aad0ecc..8abd7feeb7 100644
--- a/src/library/scala/concurrent/Future.scala
+++ b/src/library/scala/concurrent/Future.scala
@@ -20,17 +20,20 @@ import scala.collection.generic.CanBuildFrom
import scala.reflect.ClassTag
-/** The trait that represents futures.
+/** A `Future` represents a value which may or may not *currently* be available,
+ * but will be available at some point, or an exception if that value could not be made available.
*
- * Asynchronous computations that yield futures are created with the `Future.apply` call:
+ * Asynchronous computations that yield futures are created with the `Future.apply` call and are computed using a supplied `ExecutionContext`,
+ * which can be backed by a Thread pool.
*
* {{{
+ * import ExecutionContext.Implicits.global
* val s = "Hello"
* val f: Future[String] = Future {
* s + " future!"
* }
- * f onSuccess {
- * case msg => println(msg)
+ * f foreach {
+ * msg => println(msg)
* }
* }}}
*
@@ -88,6 +91,7 @@ import scala.reflect.ClassTag
* thread. That is, the implementation may run multiple callbacks
* in a batch within a single `execute()` and it may run
* `execute()` either immediately or asynchronously.
+ * Completion of the Future must *happen-before* the invocation of the callback.
*/
trait Future[+T] extends Awaitable[T] {
import Future.{ InternalCallbackExecutor => internalExecutor }
@@ -101,9 +105,13 @@ trait Future[+T] extends Awaitable[T] {
* If the future has already been completed with a value,
* this will either be applied immediately or be scheduled asynchronously.
*
+ * Note that the returned value of `pf` will be discarded.
+ *
* $swallowsExceptions
* $multipleCallbacks
* $callbackInContext
+ *
+ * @group Callbacks
*/
@deprecated("use `foreach` or `onComplete` instead (keep in mind that they take total rather than partial functions)", "2.12")
def onSuccess[U](pf: PartialFunction[T, U])(implicit executor: ExecutionContext): Unit = onComplete {
@@ -122,9 +130,13 @@ trait Future[+T] extends Awaitable[T] {
*
* Will not be called in case that the future is completed with a value.
*
+ * Note that the returned value of `pf` will be discarded.
+ *
* $swallowsExceptions
* $multipleCallbacks
* $callbackInContext
+ *
+ * @group Callbacks
*/
@deprecated("use `onComplete` or `failed.foreach` instead (keep in mind that they take total rather than partial functions)", "2.12")
def onFailure[U](@deprecatedName('callback) pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Unit = onComplete {
@@ -139,24 +151,28 @@ trait Future[+T] extends Awaitable[T] {
* If the future has already been completed,
* this will either be applied immediately or be scheduled asynchronously.
*
+ * Note that the returned value of `f` will be discarded.
+ *
* $swallowsExceptions
* $multipleCallbacks
* $callbackInContext
*
* @tparam U only used to accept any return type of the given callback function
* @param f the function to be executed when this `Future` completes
+ * @group Callbacks
*/
def onComplete[U](@deprecatedName('func) f: Try[T] => U)(implicit executor: ExecutionContext): Unit
/* Miscellaneous */
- /** Returns whether the future has already been completed with
+ /** Returns whether the future had already been completed with
* a value or an exception.
*
* $nonDeterministic
*
- * @return `true` if the future is already completed, `false` otherwise
+ * @return `true` if the future was completed, `false` otherwise
+ * @group Polling
*/
def isCompleted: Boolean
@@ -164,12 +180,13 @@ trait Future[+T] extends Awaitable[T] {
*
* $nonDeterministic
*
- * If the future is not completed the returned value will be `None`.
- * If the future is completed the value will be `Some(Success(t))`
- * if it contains a valid result, or `Some(Failure(error))` if it contains
+ * If the future was not completed the returned value will be `None`.
+ * If the future was completed the value will be `Some(Success(t))`
+ * if it contained a valid result, or `Some(Failure(error))` if it contained
* an exception.
*
* @return `None` if the `Future` wasn't completed, `Some` if it was.
+ * @group Polling
*/
def value: Option[Try[T]]
@@ -182,6 +199,7 @@ trait Future[+T] extends Awaitable[T] {
* If the original `Future` is successful, the returned `Future` is failed with a `NoSuchElementException`.
*
* @return a failed projection of this `Future`.
+ * @group Transformations
*/
def failed: Future[Throwable] =
transform({
@@ -201,6 +219,7 @@ trait Future[+T] extends Awaitable[T] {
* @tparam U only used to accept any return type of the given callback function
* @param f the function which will be executed if this `Future` completes with a result,
* the return value of `f` will be discarded.
+ * @group Callbacks
*/
def foreach[U](f: T => U)(implicit executor: ExecutionContext): Unit = onComplete { _ foreach f }
@@ -209,10 +228,11 @@ trait Future[+T] extends Awaitable[T] {
* exception thrown when 's' or 'f' is applied, that exception will be propagated
* to the resulting future.
*
- * @tparam S the type of the returned `Future`
- * @param s function that transforms a successful result of the receiver into a successful result of the returned future
- * @param f function that transforms a failure of the receiver into a failure of the returned future
- * @return a `Future` that will be completed with the transformed value
+ * @tparam S the type of the returned `Future`
+ * @param s function that transforms a successful result of the receiver into a successful result of the returned future
+ * @param f function that transforms a failure of the receiver into a failure of the returned future
+ * @return a `Future` that will be completed with the transformed value
+ * @group Transformations
*/
def transform[S](s: T => S, f: Throwable => Throwable)(implicit executor: ExecutionContext): Future[S] =
transform {
@@ -224,9 +244,10 @@ trait Future[+T] extends Awaitable[T] {
* of this Future. If there is any non-fatal exception thrown when 'f'
* is applied then that exception will be propagated to the resulting future.
*
- * @tparam S the type of the returned `Future`
- * @param f function that transforms the result of this future
- * @return a `Future` that will be completed with the transformed value
+ * @tparam S the type of the returned `Future`
+ * @param f function that transforms the result of this future
+ * @return a `Future` that will be completed with the transformed value
+ * @group Transformations
*/
def transform[S](f: Try[T] => Try[S])(implicit executor: ExecutionContext): Future[S]
@@ -234,9 +255,10 @@ trait Future[+T] extends Awaitable[T] {
* of this Future. If there is any non-fatal exception thrown when 'f'
* is applied then that exception will be propagated to the resulting future.
*
- * @tparam S the type of the returned `Future`
- * @param f function that transforms the result of this future
- * @return a `Future` that will be completed with the transformed value
+ * @tparam S the type of the returned `Future`
+ * @param f function that transforms the result of this future
+ * @return a `Future` that will be completed with the transformed value
+ * @group Transformations
*/
def transformWith[S](f: Try[T] => Future[S])(implicit executor: ExecutionContext): Future[S]
@@ -257,11 +279,12 @@ trait Future[+T] extends Awaitable[T] {
* and `withFilter`. See [[scala.concurrent.Future#flatMap]] for an example of such a comprehension.
*
*
- * @tparam S the type of the returned `Future`
- * @param f the function which will be applied to the successful result of this `Future`
- * @return a `Future` which will be completed with the result of the application of the function
+ * @tparam S the type of the returned `Future`
+ * @param f the function which will be applied to the successful result of this `Future`
+ * @return a `Future` which will be completed with the result of the application of the function
+ * @group Transformations
*/
- def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S] = transform(_.map(f))
+ def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S] = transform(_ map f)
/** Creates a new future by applying a function to the successful result of
* this future, and returns the result of the function as the new future.
@@ -270,9 +293,10 @@ trait Future[+T] extends Awaitable[T] {
*
* $forComprehensionExamples
*
- * @tparam S the type of the returned `Future`
- * @param f the function which will be applied to the successful result of this `Future`
- * @return a `Future` which will be completed with the result of the application of the function
+ * @tparam S the type of the returned `Future`
+ * @param f the function which will be applied to the successful result of this `Future`
+ * @return a `Future` which will be completed with the result of the application of the function
+ * @group Transformations
*/
def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): Future[S] = transformWith {
case Success(s) => f(s)
@@ -282,7 +306,8 @@ trait Future[+T] extends Awaitable[T] {
/** Creates a new future with one level of nesting flattened, this method is equivalent
* to `flatMap(identity)`.
*
- * @tparam S the type of the returned `Future`
+ * @tparam S the type of the returned `Future`
+ * @group Transformations
*/
def flatten[S](implicit ev: T <:< Future[S]): Future[S] = flatMap(ev)(internalExecutor)
@@ -302,13 +327,15 @@ trait Future[+T] extends Awaitable[T] {
* Await.result(h, Duration.Zero) // throw a NoSuchElementException
* }}}
*
- * @param p the predicate to apply to the successful result of this `Future`
- * @return a `Future` which will hold the successful result of this `Future` if it matches the predicate or a `NoSuchElementException`
+ * @param p the predicate to apply to the successful result of this `Future`
+ * @return a `Future` which will hold the successful result of this `Future` if it matches the predicate or a `NoSuchElementException`
+ * @group Transformations
*/
def filter(@deprecatedName('pred) p: T => Boolean)(implicit executor: ExecutionContext): Future[T] =
map { r => if (p(r)) r else throw new NoSuchElementException("Future.filter predicate is not satisfied") }
/** Used by for-comprehensions.
+ * @group Transformations
*/
final def withFilter(p: T => Boolean)(implicit executor: ExecutionContext): Future[T] = filter(p)(executor)
@@ -332,9 +359,10 @@ trait Future[+T] extends Awaitable[T] {
* Await.result(h, Duration.Zero) // throw a NoSuchElementException
* }}}
*
- * @tparam S the type of the returned `Future`
- *  @param pf the `PartialFunction` to apply to the successful result of this `Future`
- * @return a `Future` holding the result of application of the `PartialFunction` or a `NoSuchElementException`
+ * @tparam S the type of the returned `Future`
+ * @param pf the `PartialFunction` to apply to the successful result of this `Future`
+ * @return a `Future` holding the result of application of the `PartialFunction` or a `NoSuchElementException`
+ * @group Transformations
*/
def collect[S](pf: PartialFunction[T, S])(implicit executor: ExecutionContext): Future[S] =
map {
@@ -353,9 +381,10 @@ trait Future[+T] extends Awaitable[T] {
* Future (6 / 2) recover { case e: ArithmeticException => 0 } // result: 3
* }}}
*
- * @tparam U the type of the returned `Future`
- * @param pf the `PartialFunction` to apply if this `Future` fails
- * @return a `Future` with the successful value of this `Future` or the result of the `PartialFunction`
+ * @tparam U the type of the returned `Future`
+ * @param pf the `PartialFunction` to apply if this `Future` fails
+ * @return a `Future` with the successful value of this `Future` or the result of the `PartialFunction`
+ * @group Transformations
*/
def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U] =
transform { _ recover pf }
@@ -373,9 +402,10 @@ trait Future[+T] extends Awaitable[T] {
* Future (6 / 0) recoverWith { case e: ArithmeticException => f } // result: Int.MaxValue
* }}}
*
- * @tparam U the type of the returned `Future`
- * @param pf the `PartialFunction` to apply if this `Future` fails
- * @return a `Future` with the successful value of this `Future` or the outcome of the `Future` returned by the `PartialFunction`
+ * @tparam U the type of the returned `Future`
+ * @param pf the `PartialFunction` to apply if this `Future` fails
+ * @return a `Future` with the successful value of this `Future` or the outcome of the `Future` returned by the `PartialFunction`
+ * @group Transformations
*/
def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U] =
transformWith {
@@ -391,9 +421,10 @@ trait Future[+T] extends Awaitable[T] {
* Otherwise, if `that` future fails, the resulting future is failed
* with the throwable stored in `that`.
*
- * @tparam U the type of the other `Future`
- * @param that the other `Future`
- * @return a `Future` with the results of both futures or the failure of the first of them that failed
+ * @tparam U the type of the other `Future`
+ * @param that the other `Future`
+ * @return a `Future` with the results of both futures or the failure of the first of them that failed
+ * @group Transformations
*/
def zip[U](that: Future[U]): Future[(T, U)] = {
implicit val ec = internalExecutor
@@ -410,11 +441,12 @@ trait Future[+T] extends Awaitable[T] {
* If the application of `f` throws a throwable, the resulting future
* is failed with that throwable if it is non-fatal.
*
- * @tparam U the type of the other `Future`
- * @tparam R the type of the resulting `Future`
- * @param that the other `Future`
- * @param f the function to apply to the results of `this` and `that`
- * @return a `Future` with the result of the application of `f` to the results of `this` and `that`
+ * @tparam U the type of the other `Future`
+ * @tparam R the type of the resulting `Future`
+ * @param that the other `Future`
+ * @param f the function to apply to the results of `this` and `that`
+ * @return a `Future` with the result of the application of `f` to the results of `this` and `that`
+ * @group Transformations
*/
def zipWith[U, R](that: Future[U])(f: (T, U) => R)(implicit executor: ExecutionContext): Future[R] =
flatMap(r1 => that.map(r2 => f(r1, r2)))(internalExecutor)
@@ -433,9 +465,10 @@ trait Future[+T] extends Awaitable[T] {
* h foreach println // Eventually prints 5
* }}}
*
- * @tparam U the type of the other `Future` and the resulting `Future`
- * @param that the `Future` whose result we want to use if this `Future` fails.
- * @return a `Future` with the successful result of this or that `Future` or the failure of this `Future` if both fail
+ * @tparam U the type of the other `Future` and the resulting `Future`
+ * @param that the `Future` whose result we want to use if this `Future` fails.
+ * @return a `Future` with the successful result of this or that `Future` or the failure of this `Future` if both fail
+ * @group Transformations
*/
def fallbackTo[U >: T](that: Future[U]): Future[U] =
if (this eq that) this
@@ -447,9 +480,10 @@ trait Future[+T] extends Awaitable[T] {
/** Creates a new `Future[S]` which is completed with this `Future`'s result if
* that conforms to `S`'s erased type or a `ClassCastException` otherwise.
*
- * @tparam S the type of the returned `Future`
- * @param tag the `ClassTag` which will be used to cast the result of this `Future`
- * @return a `Future` holding the casted result of this `Future` or a `ClassCastException` otherwise
+ * @tparam S the type of the returned `Future`
+ * @param tag the `ClassTag` which will be used to cast the result of this `Future`
+ * @return a `Future` holding the casted result of this `Future` or a `ClassCastException` otherwise
+ * @group Transformations
*/
def mapTo[S](implicit tag: ClassTag[S]): Future[S] = {
implicit val ec = internalExecutor
@@ -484,9 +518,12 @@ trait Future[+T] extends Awaitable[T] {
* }
* }}}
*
- * @tparam U only used to accept any return type of the given `PartialFunction`
- * @param pf a `PartialFunction` which will be conditionally applied to the outcome of this `Future`
- * @return a `Future` which will be completed with the exact same outcome as this `Future` but after the `PartialFunction` has been executed.
+ * $swallowsExceptions
+ *
+ * @tparam U only used to accept any return type of the given `PartialFunction`
+ * @param pf a `PartialFunction` which will be conditionally applied to the outcome of this `Future`
+ * @return a `Future` which will be completed with the exact same outcome as this `Future` but after the `PartialFunction` has been executed.
+ * @group Callbacks
*/
def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T] =
transform {
@@ -598,6 +635,13 @@ object Future {
/** Starts an asynchronous computation and returns a `Future` instance with the result of that computation.
*
+ * The following expressions are equivalent:
+ *
+ * {{{
+ * val f1 = Future(expr)
+ * val f2 = Future.unit.map(_ => expr)
+ * }}}
+ *
* The result becomes available once the asynchronous computation is completed.
*
* @tparam T the type of the result
@@ -618,7 +662,7 @@ object Future {
*/
def sequence[A, M[X] <: TraversableOnce[X]](in: M[Future[A]])(implicit cbf: CanBuildFrom[M[Future[A]], A, M[A]], executor: ExecutionContext): Future[M[A]] = {
in.foldLeft(successful(cbf(in))) {
- (fr, fa) => for (r <- fr; a <- fa) yield (r += a)
+ (fr, fa) => fr.zipWith(fa)(_ += _)
}.map(_.result())(InternalCallbackExecutor)
}
@@ -791,10 +835,9 @@ object Future {
* @return the `Future` of the `TraversableOnce` of results
*/
def traverse[A, B, M[X] <: TraversableOnce[X]](in: M[A])(fn: A => Future[B])(implicit cbf: CanBuildFrom[M[A], B, M[B]], executor: ExecutionContext): Future[M[B]] =
- in.foldLeft(successful(cbf(in))) { (fr, a) =>
- val fb = fn(a)
- for (r <- fr; b <- fb) yield (r += b)
- }.map(_.result())
+ in.foldLeft(successful(cbf(in))) {
+ (fr, a) => fr.zipWith(fn(a))(_ += _)
+ }.map(_.result())(InternalCallbackExecutor)
// This is used to run callbacks which are internal
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/reflect/ClassTag.scala b/src/library/scala/reflect/ClassTag.scala
index 9dd96183da..1811d3a00f 100644
--- a/src/library/scala/reflect/ClassTag.scala
+++ b/src/library/scala/reflect/ClassTag.scala
@@ -2,7 +2,6 @@ package scala
package reflect
import java.lang.{ Class => jClass }
-import scala.runtime.ScalaRunTime.arrayElementClass
/**
*
@@ -102,10 +101,10 @@ trait ClassTag[T] extends ClassManifestDeprecatedApis[T] with Equals with Serial
// case class accessories
override def canEqual(x: Any) = x.isInstanceOf[ClassTag[_]]
override def equals(x: Any) = x.isInstanceOf[ClassTag[_]] && this.runtimeClass == x.asInstanceOf[ClassTag[_]].runtimeClass
- override def hashCode = scala.runtime.ScalaRunTime.hash(runtimeClass)
+ override def hashCode = runtimeClass.##
override def toString = {
def prettyprint(clazz: jClass[_]): String =
- if (clazz.isArray) s"Array[${prettyprint(arrayElementClass(clazz))}]" else
+ if (clazz.isArray) s"Array[${prettyprint(clazz.getComponentType)}]" else
clazz.getName
prettyprint(runtimeClass)
}
diff --git a/src/library/scala/runtime/ArrayRuntime.java b/src/library/scala/runtime/ArrayRuntime.java
deleted file mode 100644
index 1a0f748931..0000000000
--- a/src/library/scala/runtime/ArrayRuntime.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/* __ *\
-** ________ ___ / / ___ Scala API **
-** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
-
-
-
-package scala.runtime;
-
-/**
- * Methods on Java arrays
- */
-class ArrayRuntime {
- static boolean[] cloneArray(boolean[] array) { return array.clone(); }
- static byte[] cloneArray(byte[] array) { return array.clone(); }
- static short[] cloneArray(short[] array) { return array.clone(); }
- static char[] cloneArray(char[] array) { return array.clone(); }
- static int[] cloneArray(int[] array) { return array.clone(); }
- static long[] cloneArray(long[] array) { return array.clone(); }
- static float[] cloneArray(float[] array) { return array.clone(); }
- static double[] cloneArray(double[] array) { return array.clone(); }
- static Object[] cloneArray(Object[] array) { return array.clone(); }
-}
diff --git a/src/library/scala/runtime/Boxed.scala b/src/library/scala/runtime/Boxed.scala
deleted file mode 100644
index 933444773d..0000000000
--- a/src/library/scala/runtime/Boxed.scala
+++ /dev/null
@@ -1,12 +0,0 @@
-/* __ *\
-** ________ ___ / / ___ Scala API **
-** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
-
-package scala
-package runtime
-
-trait Boxed { }
diff --git a/src/library/scala/runtime/BoxesRunTime.java b/src/library/scala/runtime/BoxesRunTime.java
index 9ae118f43f..6b3874fc1f 100644
--- a/src/library/scala/runtime/BoxesRunTime.java
+++ b/src/library/scala/runtime/BoxesRunTime.java
@@ -198,70 +198,6 @@ public final class BoxesRunTime
}
}
- /** Hashcode algorithm is driven by the requirements imposed
- * by primitive equality semantics, namely that equal objects
- * have equal hashCodes. The first priority are the integral/char
- * types, which already have the same hashCodes for the same
- * values except for Long. So Long's hashCode is altered to
- * conform to Int's for all values in Int's range.
- *
- * Float is problematic because it's far too small to hold
- * all the Ints, so for instance Int.MaxValue.toFloat claims
- * to be == to each of the largest 64 Ints. There is no way
- * to preserve equals/hashCode alignment without compromising
- * the hashCode distribution, so Floats are only guaranteed
- * to have the same hashCode for whole Floats in the range
- * Short.MinValue to Short.MaxValue (2^16 total.)
- *
- * Double has its hashCode altered to match the entire Int range,
- * but is not guaranteed beyond that. (But could/should it be?
- * The hashCode is only 32 bits so this is a more tractable
- * issue than Float's, but it might be better simply to exclude it.)
- *
- * Note: BigInt and BigDecimal, being arbitrary precision, could
- * be made consistent with all other types for the Int range, but
- * as yet have not.
- *
- * Note: Among primitives, Float.NaN != Float.NaN, but the boxed
- * versions are equal. This still needs reconciliation.
- */
- public static int hashFromLong(java.lang.Long n) {
- int iv = n.intValue();
- if (iv == n.longValue()) return iv;
- else return n.hashCode();
- }
- public static int hashFromDouble(java.lang.Double n) {
- int iv = n.intValue();
- double dv = n.doubleValue();
- if (iv == dv) return iv;
-
- long lv = n.longValue();
- if (lv == dv) return java.lang.Long.hashCode(lv);
-
- float fv = n.floatValue();
- if (fv == dv) return java.lang.Float.hashCode(fv);
- else return n.hashCode();
- }
- public static int hashFromFloat(java.lang.Float n) {
- int iv = n.intValue();
- float fv = n.floatValue();
- if (iv == fv) return iv;
-
- long lv = n.longValue();
- if (lv == fv) return java.lang.Long.hashCode(lv);
- else return n.hashCode();
- }
- public static int hashFromNumber(java.lang.Number n) {
- if (n instanceof java.lang.Long) return hashFromLong((java.lang.Long)n);
- else if (n instanceof java.lang.Double) return hashFromDouble((java.lang.Double)n);
- else if (n instanceof java.lang.Float) return hashFromFloat((java.lang.Float)n);
- else return n.hashCode();
- }
- public static int hashFromObject(Object a) {
- if (a instanceof Number) return hashFromNumber((Number)a);
- else return a.hashCode();
- }
-
private static int unboxCharOrInt(Object arg1, int code) {
if (code == CHAR)
return ((java.lang.Character) arg1).charValue();
diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala
index 1195f95093..b31a94576a 100644
--- a/src/library/scala/runtime/ScalaRunTime.scala
+++ b/src/library/scala/runtime/ScalaRunTime.scala
@@ -29,15 +29,6 @@ object ScalaRunTime {
private def isArrayClass(clazz: jClass[_], atLevel: Int): Boolean =
clazz.isArray && (atLevel == 1 || isArrayClass(clazz.getComponentType, atLevel - 1))
- def isValueClass(clazz: jClass[_]) = clazz.isPrimitive()
-
- // includes specialized subclasses and future proofed against hypothetical TupleN (for N > 22)
- def isTuple(x: Any) = x != null && x.getClass.getName.startsWith("scala.Tuple")
- def isAnyVal(x: Any) = x match {
- case _: Byte | _: Short | _: Char | _: Int | _: Long | _: Float | _: Double | _: Boolean | _: Unit => true
- case _ => false
- }
-
// A helper method to make my life in the pattern matcher a lot easier.
def drop[Repr](coll: Repr, num: Int)(implicit traversable: IsTraversableLike[Repr]): Repr =
traversable conversion coll drop num
@@ -50,15 +41,6 @@ object ScalaRunTime {
else java.lang.reflect.Array.newInstance(clazz, 0).getClass
}
- /** Return the class object representing elements in arrays described by a given schematic.
- */
- def arrayElementClass(schematic: Any): jClass[_] = schematic match {
- case cls: jClass[_] => cls.getComponentType
- case tag: ClassTag[_] => tag.runtimeClass
- case _ =>
- throw new UnsupportedOperationException(s"unsupported schematic $schematic (${schematic.getClass})")
- }
-
/** Return the class object representing an unboxed value type,
* e.g., classOf[int], not classOf[java.lang.Integer]. The compiler
* rewrites expressions like 5.getClass to come here.
@@ -116,15 +98,15 @@ object ScalaRunTime {
}
def array_clone(xs: AnyRef): AnyRef = xs match {
- case x: Array[AnyRef] => ArrayRuntime.cloneArray(x)
- case x: Array[Int] => ArrayRuntime.cloneArray(x)
- case x: Array[Double] => ArrayRuntime.cloneArray(x)
- case x: Array[Long] => ArrayRuntime.cloneArray(x)
- case x: Array[Float] => ArrayRuntime.cloneArray(x)
- case x: Array[Char] => ArrayRuntime.cloneArray(x)
- case x: Array[Byte] => ArrayRuntime.cloneArray(x)
- case x: Array[Short] => ArrayRuntime.cloneArray(x)
- case x: Array[Boolean] => ArrayRuntime.cloneArray(x)
+ case x: Array[AnyRef] => x.clone()
+ case x: Array[Int] => x.clone()
+ case x: Array[Double] => x.clone()
+ case x: Array[Long] => x.clone()
+ case x: Array[Float] => x.clone()
+ case x: Array[Char] => x.clone()
+ case x: Array[Byte] => x.clone()
+ case x: Array[Short] => x.clone()
+ case x: Array[Boolean] => x.clone()
case x: Array[Unit] => x
case null => throw new NullPointerException
}
@@ -157,9 +139,6 @@ object ScalaRunTime {
// More background at ticket #2318.
def ensureAccessible(m: JMethod): JMethod = scala.reflect.ensureAccessible(m)
- def checkInitialized[T <: AnyRef](x: T): T =
- if (x == null) throw new UninitializedError else x
-
def _toString(x: Product): String =
x.productIterator.mkString(x.productPrefix + "(", ",", ")")
@@ -179,71 +158,9 @@ object ScalaRunTime {
}
}
- /** Fast path equality method for inlining; used when -optimise is set.
- */
- @inline def inlinedEquals(x: Object, y: Object): Boolean =
- if (x eq y) true
- else if (x eq null) false
- else if (x.isInstanceOf[java.lang.Number]) BoxesRunTime.equalsNumObject(x.asInstanceOf[java.lang.Number], y)
- else if (x.isInstanceOf[java.lang.Character]) BoxesRunTime.equalsCharObject(x.asInstanceOf[java.lang.Character], y)
- else x.equals(y)
-
- def _equals(x: Product, y: Any): Boolean = y match {
- case y: Product if x.productArity == y.productArity => x.productIterator sameElements y.productIterator
- case _ => false
- }
-
- // hashcode -----------------------------------------------------------
- //
- // Note that these are the implementations called by ##, so they
- // must not call ## themselves.
-
- def hash(x: Any): Int =
- if (x == null) 0
- else if (x.isInstanceOf[java.lang.Number]) BoxesRunTime.hashFromNumber(x.asInstanceOf[java.lang.Number])
- else x.hashCode
-
- def hash(dv: Double): Int = {
- val iv = dv.toInt
- if (iv == dv) return iv
-
- val lv = dv.toLong
- if (lv == dv) return lv.hashCode
-
- val fv = dv.toFloat
- if (fv == dv) fv.hashCode else dv.hashCode
- }
- def hash(fv: Float): Int = {
- val iv = fv.toInt
- if (iv == fv) return iv
-
- val lv = fv.toLong
- if (lv == fv) hash(lv)
- else fv.hashCode
- }
- def hash(lv: Long): Int = {
- val low = lv.toInt
- val lowSign = low >>> 31
- val high = (lv >>> 32).toInt
- low ^ (high + lowSign)
- }
- def hash(x: Number): Int = runtime.BoxesRunTime.hashFromNumber(x)
-
- // The remaining overloads are here for completeness, but the compiler
- // inlines these definitions directly so they're not generally used.
- def hash(x: Int): Int = x
- def hash(x: Short): Int = x.toInt
- def hash(x: Byte): Int = x.toInt
- def hash(x: Char): Int = x.toInt
- def hash(x: Boolean): Int = if (x) true.hashCode else false.hashCode
- def hash(x: Unit): Int = 0
-
- /** A helper method for constructing case class equality methods,
- * because existential types get in the way of a clean outcome and
- * it's performing a series of Any/Any equals comparisons anyway.
- * See ticket #2867 for specifics.
- */
- def sameElements(xs1: scala.collection.Seq[Any], xs2: scala.collection.Seq[Any]) = xs1 sameElements xs2
+ /** Old implementation of `##`. */
+ @deprecated("Use scala.runtime.Statics.anyHash instead.", "2.12.0")
+ def hash(x: Any): Int = Statics.anyHash(x.asInstanceOf[Object])
/** Given any Scala value, convert it to a String.
*
@@ -266,6 +183,9 @@ object ScalaRunTime {
def isScalaClass(x: AnyRef) = packageOf(x) startsWith "scala."
def isScalaCompilerClass(x: AnyRef) = packageOf(x) startsWith "scala.tools.nsc."
+ // includes specialized subclasses and future proofed against hypothetical TupleN (for N > 22)
+ def isTuple(x: Any) = x != null && x.getClass.getName.startsWith("scala.Tuple")
+
// We use reflection because the scala.xml package might not be available
def isSubClassOf(potentialSubClass: Class[_], ofClass: String) =
try {
@@ -345,17 +265,4 @@ object ScalaRunTime {
nl + s + "\n"
}
-
- def box[T](clazz: jClass[T]): jClass[_] = clazz match {
- case java.lang.Byte.TYPE => classOf[java.lang.Byte]
- case java.lang.Short.TYPE => classOf[java.lang.Short]
- case java.lang.Character.TYPE => classOf[java.lang.Character]
- case java.lang.Integer.TYPE => classOf[java.lang.Integer]
- case java.lang.Long.TYPE => classOf[java.lang.Long]
- case java.lang.Float.TYPE => classOf[java.lang.Float]
- case java.lang.Double.TYPE => classOf[java.lang.Double]
- case java.lang.Void.TYPE => classOf[scala.runtime.BoxedUnit]
- case java.lang.Boolean.TYPE => classOf[java.lang.Boolean]
- case _ => clazz
- }
}
diff --git a/src/library/scala/runtime/Statics.java b/src/library/scala/runtime/Statics.java
index 485511ecbb..62390cb9d0 100644
--- a/src/library/scala/runtime/Statics.java
+++ b/src/library/scala/runtime/Statics.java
@@ -36,10 +36,11 @@ public final class Statics {
}
public static int longHash(long lv) {
- if ((int)lv == lv)
- return (int)lv;
- else
- return (int)(lv ^ (lv >>> 32));
+ int iv = (int)lv;
+ if (iv == lv)
+ return iv;
+
+ return java.lang.Long.hashCode(lv);
}
public static int doubleHash(double dv) {
@@ -47,16 +48,15 @@ public final class Statics {
if (iv == dv)
return iv;
- float fv = (float)dv;
- if (fv == dv)
- return java.lang.Float.floatToIntBits(fv);
-
long lv = (long)dv;
if (lv == dv)
- return (int)lv;
+ return java.lang.Long.hashCode(lv);
+
+ float fv = (float)dv;
+ if (fv == dv)
+ return java.lang.Float.hashCode(fv);
- lv = Double.doubleToLongBits(dv);
- return (int)(lv ^ (lv >>> 32));
+ return java.lang.Double.hashCode(dv);
}
public static int floatHash(float fv) {
@@ -66,11 +66,39 @@ public final class Statics {
long lv = (long)fv;
if (lv == fv)
- return (int)(lv^(lv>>>32));
+ return java.lang.Long.hashCode(lv);
- return java.lang.Float.floatToIntBits(fv);
+ return java.lang.Float.hashCode(fv);
}
+ /**
+ * Hashcode algorithm is driven by the requirements imposed
+ * by primitive equality semantics, namely that equal objects
+ * have equal hashCodes. The first priority are the integral/char
+ * types, which already have the same hashCodes for the same
+ * values except for Long. So Long's hashCode is altered to
+ * conform to Int's for all values in Int's range.
+ *
+ * Float is problematic because it's far too small to hold
+ * all the Ints, so for instance Int.MaxValue.toFloat claims
+ * to be == to each of the largest 64 Ints. There is no way
+ * to preserve equals/hashCode alignment without compromising
+ * the hashCode distribution, so Floats are only guaranteed
+ * to have the same hashCode for whole Floats in the range
+ * Short.MinValue to Short.MaxValue (2^16 total.)
+ *
+ * Double has its hashCode altered to match the entire Int range,
+ * but is not guaranteed beyond that. (But could/should it be?
+ * The hashCode is only 32 bits so this is a more tractable
+ * issue than Float's, but it might be better simply to exclude it.)
+ *
+ * Note: BigInt and BigDecimal, being arbitrary precision, could
+ * be made consistent with all other types for the Int range, but
+ * as yet have not.
+ *
+ * Note: Among primitives, Float.NaN != Float.NaN, but the boxed
+ * versions are equal. This still needs reconciliation.
+ */
public static int anyHash(Object x) {
if (x == null)
return 0;
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/library/scala/sys/process/package.scala b/src/library/scala/sys/process/package.scala
index 0e9a1bfc56..ff0fd920c9 100644
--- a/src/library/scala/sys/process/package.scala
+++ b/src/library/scala/sys/process/package.scala
@@ -203,9 +203,9 @@ package scala.sys {
package object process extends ProcessImplicits {
/** The arguments passed to `java` when creating this process */
def javaVmArguments: List[String] = {
- import scala.collection.JavaConversions._
+ import scala.collection.JavaConverters._
- java.lang.management.ManagementFactory.getRuntimeMXBean().getInputArguments().toList
+ java.lang.management.ManagementFactory.getRuntimeMXBean.getInputArguments.asScala.toList
}
/** The input stream of this process */
def stdin = java.lang.System.in
diff --git a/src/library/scala/util/control/Exception.scala b/src/library/scala/util/control/Exception.scala
index 8aa4073a51..64f491d7f0 100644
--- a/src/library/scala/util/control/Exception.scala
+++ b/src/library/scala/util/control/Exception.scala
@@ -13,21 +13,136 @@ package control
import scala.reflect.{ ClassTag, classTag }
import scala.language.implicitConversions
-
/** Classes representing the components of exception handling.
- * Each class is independently composable. Some example usages:
+ *
+ * Each class is independently composable.
+ *
+ * This class differs from [[scala.util.Try]] in that it focuses on composing exception handlers rather than
+ * composing behavior. All behavior should be composed first and fed to a [[Catch]] object using one of the
+ * `opt`, `either` or `withTry` methods. Taken together the classes provide a DSL for composing catch and finally
+ * behaviors.
+ *
+ * === Examples ===
+ *
+ * Create a `Catch` which handles specified exceptions.
* {{{
* import scala.util.control.Exception._
* import java.net._
*
* val s = "http://www.scala-lang.org/"
- * val x1 = catching(classOf[MalformedURLException]) opt new URL(s)
- * val x2 = catching(classOf[MalformedURLException], classOf[NullPointerException]) either new URL(s)
+ *
+ * // Some(http://www.scala-lang.org/)
+ * val x1: Option[URL] = catching(classOf[MalformedURLException]) opt new URL(s)
+ *
+ * // Right(http://www.scala-lang.org/)
+ * val x2: Either[Throwable,URL] =
+ * catching(classOf[MalformedURLException], classOf[NullPointerException]) either new URL(s)
+ *
+ * // Success(http://www.scala-lang.org/)
+ * val x3: Try[URL] = catching(classOf[MalformedURLException], classOf[NullPointerException]) withTry new URL(s)
+ *
+ * val defaultUrl = new URL("http://example.com")
+ * // URL(http://example.com) because htt/xx throws MalformedURLException
+ * val x4: URL = failAsValue(classOf[MalformedURLException])(defaultUrl)(new URL("htt/xx"))
+ * }}}
+ *
+ * Create a `Catch` which logs exceptions using `handling` and `by`.
+ * {{{
+ * def log(t: Throwable): Unit = t.printStackTrace
+ *
+ * val withThrowableLogging: Catch[Unit] = handling(classOf[MalformedURLException]) by (log)
+ *
+ * def printUrl(url: String) : Unit = {
+ * val con = new URL(url) openConnection()
+ * val source = scala.io.Source.fromInputStream(con.getInputStream())
+ * source.getLines.foreach(println)
+ * }
+ *
+ * val badUrl = "htt/xx"
+ * // Prints stacktrace,
+ * // java.net.MalformedURLException: no protocol: htt/xx
+ * // at java.net.URL.<init>(URL.java:586)
+ * withThrowableLogging { printUrl(badUrl) }
+ *
+ * val goodUrl = "http://www.scala-lang.org/"
+ * // Prints page content,
+ * // &lt;!DOCTYPE html&gt;
+ * // &lt;html&gt;
+ * withThrowableLogging { printUrl(goodUrl) }
+ * }}}
+ *
+ * Use `unwrapping` to create a `Catch` that unwraps exceptions before rethrowing.
+ * {{{
+ * class AppException(cause: Throwable) extends RuntimeException(cause)
+ *
+ * val unwrappingCatch: Catch[Nothing] = unwrapping(classOf[AppException])
+ *
+ * def calcResult: Int = throw new AppException(new NullPointerException)
+ *
+ * // Throws NPE not AppException,
+ * // java.lang.NullPointerException
+ * // at .calcResult(&lt;console&gt;:17)
+ * val result = unwrappingCatch(calcResult)
* }}}
*
- * This class differs from `scala.util.Try` in that it focuses on composing exception handlers rather than
- * composing behavior. All behavior should be composed first and fed to a `Catch` object using one of the
- * `opt` or `either` methods.
+ * Use `failAsValue` to provide a default when a specified exception is caught.
+ *
+ * {{{
+ * val inputDefaulting: Catch[Int] = failAsValue(classOf[NumberFormatException])(0)
+ * val candidatePick = "seven" // scala.io.StdIn.readLine()
+ *
+ * // Int = 0
+ * val pick = inputDefaulting(candidatePick.toInt)
+ * }}}
+ *
+ * Compose multiple `Catch`s with `or` to build a `Catch` that provides default values varied by exception.
+ * {{{
+ * val formatDefaulting: Catch[Int] = failAsValue(classOf[NumberFormatException])(0)
+ * val nullDefaulting: Catch[Int] = failAsValue(classOf[NullPointerException])(-1)
+ * val otherDefaulting: Catch[Int] = nonFatalCatch withApply(_ => -100)
+ *
+ * val combinedDefaulting: Catch[Int] = formatDefaulting or nullDefaulting or otherDefaulting
+ *
+ * def p(s: String): Int = s.length * s.toInt
+ *
+ * // Int = 0
+ * combinedDefaulting(p("tenty-nine"))
+ *
+ * // Int = -1
+ * combinedDefaulting(p(null: String))
+ *
+ * // Int = -100
+ * combinedDefaulting(throw new IllegalStateException)
+ *
+ * // Int = 22
+ * combinedDefaulting(p("11"))
+ * }}}
+ *
+ * @groupname composition-catch Catch behavior composition
+ * @groupprio composition-catch 10
+ * @groupdesc composition-catch Build Catch objects from exception lists and catch logic
+ *
+ * @groupname composition-finally Finally behavior composition
+ * @groupprio composition-finally 20
+ * @groupdesc composition-finally Build Catch objects from finally logic
+ *
+ * @groupname canned-behavior General purpose catch objects
+ * @groupprio canned-behavior 30
+ * @groupdesc canned-behavior Catch objects with predefined behavior. Use combinator methods to compose additional behavior.
+ *
+ * @groupname dsl DSL behavior composition
+ * @groupprio dsl 40
+ * @groupdesc dsl Expressive Catch behavior composition
+ *
+ * @groupname composition-catch-promiscuously Promiscuous Catch behaviors
+ * @groupprio composition-catch-promiscuously 50
+ * @groupdesc composition-catch-promiscuously Useful if catching `ControlThrowable` or `InterruptedException` is required.
+ *
+ * @groupname logic-container Logic Containers
+ * @groupprio logic-container 60
+ * @groupdesc logic-container Containers for catch and finally behavior.
+ *
+ * @define protectedExceptions `ControlThrowable` or `InterruptedException`
*
* @author Paul Phillips
*/
@@ -51,6 +166,7 @@ object Exception {
/** !!! Not at all sure of every factor which goes into this,
* and/or whether we need multiple standard variations.
+ * @return true if `x` is $protectedExceptions otherwise false.
*/
def shouldRethrow(x: Throwable): Boolean = x match {
case _: ControlThrowable => true
@@ -70,7 +186,9 @@ object Exception {
override def toString() = name + "(" + desc + ")"
}
- /** A container class for finally code. */
+ /** A container class for finally code.
+ * @group logic-container
+ */
class Finally private[Exception](body: => Unit) extends Described {
protected val name = "Finally"
@@ -87,6 +205,7 @@ object Exception {
* @param pf Partial function used when applying catch logic to determine result value
* @param fin Finally logic which if defined will be invoked after catch logic
* @param rethrow Predicate on throwables determining when to rethrow a caught [[Throwable]]
+ * @group logic-container
*/
class Catch[+T](
val pf: Catcher[T],
@@ -153,23 +272,30 @@ object Exception {
final def nonFatalCatcher[T]: Catcher[T] = mkThrowableCatcher({ case NonFatal(_) => true; case _ => false }, throw _)
final def allCatcher[T]: Catcher[T] = mkThrowableCatcher(_ => true, throw _)
- /** The empty `Catch` object. */
+ /** The empty `Catch` object.
+ * @group canned-behavior
+ **/
final val noCatch: Catch[Nothing] = new Catch(nothingCatcher) withDesc "<nothing>"
- /** A `Catch` object which catches everything. */
+ /** A `Catch` object which catches everything.
+ * @group canned-behavior
+ **/
final def allCatch[T]: Catch[T] = new Catch(allCatcher[T]) withDesc "<everything>"
- /** A `Catch` object which catches non-fatal exceptions. */
+ /** A `Catch` object which catches non-fatal exceptions.
+ * @group canned-behavior
+ **/
final def nonFatalCatch[T]: Catch[T] = new Catch(nonFatalCatcher[T]) withDesc "<non-fatal>"
/** Creates a `Catch` object which will catch any of the supplied exceptions.
* Since the returned `Catch` object has no specific logic defined and will simply
- * rethrow the exceptions it catches, you will typically want to call `opt` or
- * `either` on the return value, or assign custom logic by calling "withApply".
+ * rethrow the exceptions it catches, you will typically want to call `opt`,
+ * `either` or `withTry` on the return value, or assign custom logic by calling "withApply".
*
* Note that `Catch` objects automatically rethrow `ControlExceptions` and others
* which should only be caught in exceptional circumstances. If you really want
* to catch exactly what you specify, use `catchingPromiscuously` instead.
+ * @group composition-catch
*/
def catching[T](exceptions: Class[_]*): Catch[T] =
new Catch(pfFromExceptions(exceptions : _*)) withDesc (exceptions map (_.getName) mkString ", ")
@@ -178,42 +304,56 @@ object Exception {
/** Creates a `Catch` object which will catch any of the supplied exceptions.
* Unlike "catching" which filters out those in shouldRethrow, this one will
- * catch whatever you ask of it: `ControlThrowable`, `InterruptedException`,
- * `OutOfMemoryError`, you name it.
+ * catch whatever you ask of it including $protectedExceptions.
+ * @group composition-catch-promiscuously
*/
def catchingPromiscuously[T](exceptions: Class[_]*): Catch[T] = catchingPromiscuously(pfFromExceptions(exceptions : _*))
def catchingPromiscuously[T](c: Catcher[T]): Catch[T] = new Catch(c, None, _ => false)
- /** Creates a `Catch` object which catches and ignores any of the supplied exceptions. */
+ /** Creates a `Catch` object which catches and ignores any of the supplied exceptions.
+ * @group composition-catch
+ */
def ignoring(exceptions: Class[_]*): Catch[Unit] =
catching(exceptions: _*) withApply (_ => ())
- /** Creates a `Catch` object which maps all the supplied exceptions to `None`. */
+ /** Creates a `Catch` object which maps all the supplied exceptions to `None`.
+ * @group composition-catch
+ */
def failing[T](exceptions: Class[_]*): Catch[Option[T]] =
catching(exceptions: _*) withApply (_ => None)
- /** Creates a `Catch` object which maps all the supplied exceptions to the given value. */
+ /** Creates a `Catch` object which maps all the supplied exceptions to the given value.
+ * @group composition-catch
+ */
def failAsValue[T](exceptions: Class[_]*)(value: => T): Catch[T] =
catching(exceptions: _*) withApply (_ => value)
+ class By[T,R](f: T => R) {
+ def by(x: T): R = f(x)
+ }
+
/** Returns a partially constructed `Catch` object, which you must give
- * an exception handler function as an argument to `by`. Example:
+ * an exception handler function as an argument to `by`.
+ * @example
* {{{
- * handling(ex1, ex2) by (_.printStackTrace)
+ * handling(classOf[MalformedURLException], classOf[NullPointerException]) by (_.printStackTrace)
* }}}
+ * @group dsl
*/
- class By[T,R](f: T => R) {
- def by(x: T): R = f(x)
- }
+ // TODO: Add return type
def handling[T](exceptions: Class[_]*) = {
def fun(f: Throwable => T) = catching(exceptions: _*) withApply f
new By[Throwable => T, Catch[T]](fun _)
}
- /** Returns a `Catch` object with no catch logic and the argument as `Finally`. */
+ /** Returns a `Catch` object with no catch logic and the argument as the finally logic.
+ * @group composition-finally
+ */
def ultimately[T](body: => Unit): Catch[T] = noCatch andFinally body
- /** Creates a `Catch` object which unwraps any of the supplied exceptions. */
+ /** Creates a `Catch` object which unwraps any of the supplied exceptions.
+ * @group composition-catch
+ */
def unwrapping[T](exceptions: Class[_]*): Catch[T] = {
def unwrap(x: Throwable): Throwable =
if (wouldMatch(x, exceptions) && x.getCause != null) unwrap(x.getCause)
diff --git a/src/library/scala/util/matching/Regex.scala b/src/library/scala/util/matching/Regex.scala
index 6d3d015b1a..bd55fb5d04 100644
--- a/src/library/scala/util/matching/Regex.scala
+++ b/src/library/scala/util/matching/Regex.scala
@@ -182,6 +182,9 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
* val namedYears = for (m <- namedDate findAllMatchIn dates) yield m group "year"
* }}}
*
+ * Group names supplied to the constructor are preferred to inline group names
+ * when retrieving matched groups by name. Not all platforms support inline names.
+ *
* This constructor does not support options as flags, which must be
* supplied as inline flags in the pattern string: `(?idmsux-idmsux)`.
*
@@ -578,6 +581,9 @@ object Regex {
*/
trait MatchData {
+ /** Basically, wraps a platform Matcher. */
+ protected def matcher: Matcher
+
/** The source from which the match originated */
val source: CharSequence
@@ -650,16 +656,25 @@ object Regex {
private lazy val nameToIndex: Map[String, Int] = Map[String, Int]() ++ ("" :: groupNames.toList).zipWithIndex
- /** Returns the group with given name.
+ /** Returns the group with the given name.
+ *
+ * Uses explicit group names when supplied; otherwise,
+ * queries the underlying implementation for inline named groups.
+ * Not all platforms support inline group names.
*
* @param id The group name
* @return The requested group
- * @throws NoSuchElementException if the requested group name is not defined
+ * @throws IllegalArgumentException if the requested group name is not defined
*/
- def group(id: String): String = nameToIndex.get(id) match {
- case None => throw new NoSuchElementException("group name "+id+" not defined")
- case Some(index) => group(index)
- }
+ def group(id: String): String = (
+ if (groupNames.isEmpty)
+ matcher group id
+ else
+ nameToIndex.get(id) match {
+ case Some(index) => group(index)
+ case None => matcher group id
+ }
+ )
/** The matched string; equivalent to `matched.toString`. */
override def toString = matched
@@ -667,7 +682,7 @@ object Regex {
/** Provides information about a successful match. */
class Match(val source: CharSequence,
- private[matching] val matcher: Matcher,
+ protected[matching] val matcher: Matcher,
val groupNames: Seq[String]) extends MatchData {
/** The index of the first matched character. */
diff --git a/src/partest-extras/scala/tools/partest/BytecodeTest.scala b/src/partest-extras/scala/tools/partest/BytecodeTest.scala
index 290b7b434e..532dfd2a73 100644
--- a/src/partest-extras/scala/tools/partest/BytecodeTest.scala
+++ b/src/partest-extras/scala/tools/partest/BytecodeTest.scala
@@ -1,10 +1,10 @@
package scala.tools.partest
-import scala.tools.nsc.util.JavaClassPath
import scala.collection.JavaConverters._
-import scala.tools.asm.{ClassWriter, ClassReader}
+import scala.tools.asm.{ClassReader, ClassWriter}
import scala.tools.asm.tree._
-import java.io.{File => JFile, InputStream}
+import java.io.{InputStream, File => JFile}
+
import AsmNode._
/**
@@ -125,12 +125,16 @@ abstract class BytecodeTest {
cn
}
- protected lazy val classpath: JavaClassPath = {
- import scala.tools.nsc.util.ClassPath.DefaultJavaContext
+ protected lazy val classpath: scala.tools.nsc.util.ClassPath = {
+ import scala.tools.nsc.classpath.AggregateClassPath
+ import scala.tools.nsc.classpath.ClassPathFactory
import scala.tools.util.PathResolver.Defaults
+ import scala.tools.nsc.Settings
// logic inspired by scala.tools.util.PathResolver implementation
- val containers = DefaultJavaContext.classesInExpandedPath(Defaults.javaUserClassPath)
- new JavaClassPath(containers, DefaultJavaContext)
+ // `Settings` is used to check YdisableFlatCpCaching in ZipArchiveFlatClassPath
+ val factory = new ClassPathFactory(new Settings())
+ val containers = factory.classesInExpandedPath(Defaults.javaUserClassPath)
+ new AggregateClassPath(containers)
}
}
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index d2312440cc..db8ac9b0cb 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -1152,6 +1152,7 @@ trait Definitions extends api.StandardDefinitions {
lazy val ElidableMethodClass = requiredClass[scala.annotation.elidable]
lazy val ImplicitNotFoundClass = requiredClass[scala.annotation.implicitNotFound]
lazy val ImplicitAmbiguousClass = getClassIfDefined("scala.annotation.implicitAmbiguous")
+ lazy val JUnitTestClass = getClassIfDefined("org.junit.Test")
lazy val MigrationAnnotationClass = requiredClass[scala.annotation.migration]
lazy val ScalaStrictFPAttr = requiredClass[scala.annotation.strictfp]
lazy val SwitchClass = requiredClass[scala.annotation.switch]
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index 6abd7f2f19..0ac72e7d8b 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -641,6 +641,7 @@ trait StdNames {
val accessor: NameType = "accessor"
val add_ : NameType = "add"
val annotation: NameType = "annotation"
+ val anyHash: NameType = "anyHash"
val anyValClass: NameType = "anyValClass"
val apply: NameType = "apply"
val applyDynamic: NameType = "applyDynamic"
@@ -670,6 +671,7 @@ trait StdNames {
val delayedInit: NameType = "delayedInit"
val delayedInitArg: NameType = "delayedInit$body"
val dollarScope: NameType = "$scope"
+ val doubleHash: NameType = "doubleHash"
val drop: NameType = "drop"
val elem: NameType = "elem"
val noSelfType: NameType = "noSelfType"
@@ -688,13 +690,13 @@ trait StdNames {
val finalize_ : NameType = "finalize"
val find_ : NameType = "find"
val flatMap: NameType = "flatMap"
+ val floatHash: NameType = "floatHash"
val foreach: NameType = "foreach"
val freshTermName: NameType = "freshTermName"
val freshTypeName: NameType = "freshTypeName"
val get: NameType = "get"
val parameterTypes: NameType = "parameterTypes"
val hashCode_ : NameType = "hashCode"
- val hash_ : NameType = "hash"
val head : NameType = "head"
val immutable: NameType = "immutable"
val implicitly: NameType = "implicitly"
@@ -711,6 +713,7 @@ trait StdNames {
val lang: NameType = "lang"
val length: NameType = "length"
val lengthCompare: NameType = "lengthCompare"
+ val longHash: NameType = "longHash"
val macroContext : NameType = "c"
val main: NameType = "main"
val manifestToTypeTag: NameType = "manifestToTypeTag"
diff --git a/src/reflect/scala/reflect/internal/transform/Erasure.scala b/src/reflect/scala/reflect/internal/transform/Erasure.scala
index c069e2c198..412c49f571 100644
--- a/src/reflect/scala/reflect/internal/transform/Erasure.scala
+++ b/src/reflect/scala/reflect/internal/transform/Erasure.scala
@@ -113,7 +113,8 @@ trait Erasure {
def apply(tp: Type): Type = tp match {
case ConstantType(ct) =>
- if (ct.tag == ClazzTag) ConstantType(Constant(apply(ct.typeValue)))
+ // erase classOf[List[_]] to classOf[List]. special case for classOf[Unit], avoid erasing to classOf[BoxedUnit].
+ if (ct.tag == ClazzTag && ct.typeValue.typeSymbol != UnitClass) ConstantType(Constant(apply(ct.typeValue)))
else tp
case st: ThisType if st.sym.isPackageClass =>
tp
@@ -165,7 +166,7 @@ trait Erasure {
/** The erasure |T| of a type T. This is:
*
- * - For a constant type, itself.
+ * - For a constant type classOf[T], classOf[|T|], unless T is Unit. For any other constant type, itself.
* - For a type-bounds structure, the erasure of its upper bound.
* - For every other singleton type, the erasure of its supertype.
* - For a typeref scala.Array+[T] where T is an abstract type, AnyRef.
diff --git a/src/reflect/scala/reflect/io/ZipArchive.scala b/src/reflect/scala/reflect/io/ZipArchive.scala
index 42e22fda6f..262ab22ce9 100644
--- a/src/reflect/scala/reflect/io/ZipArchive.scala
+++ b/src/reflect/scala/reflect/io/ZipArchive.scala
@@ -13,7 +13,7 @@ import java.io.{ File => JFile }
import java.util.zip.{ ZipEntry, ZipFile, ZipInputStream }
import java.util.jar.Manifest
import scala.collection.mutable
-import scala.collection.convert.WrapAsScala.asScalaIterator
+import scala.collection.JavaConverters._
import scala.annotation.tailrec
/** An abstraction for zip files and streams. Everything is written the way
@@ -238,7 +238,7 @@ final class ManifestResources(val url: URL) extends ZipArchive(null) {
val root = new DirEntry("/")
val dirs = mutable.HashMap[String, DirEntry]("/" -> root)
val manifest = new Manifest(input)
- val iter = manifest.getEntries().keySet().iterator().filter(_.endsWith(".class")).map(new ZipEntry(_))
+ val iter = manifest.getEntries().keySet().iterator().asScala.filter(_.endsWith(".class")).map(new ZipEntry(_))
for (zipEntry <- iter) {
val dir = getDir(dirs, zipEntry)
diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
index bdcfcabdd5..9b0d66f41c 100644
--- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala
+++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
@@ -154,7 +154,7 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive
}
def apply(schemaAndValue: (jClass[_], Any)): ClassfileAnnotArg = schemaAndValue match {
case ConstantArg(value) => LiteralAnnotArg(Constant(value))
- case (clazz @ ArrayClass(), value: Array[_]) => ArrayAnnotArg(value map (x => apply(ScalaRunTime.arrayElementClass(clazz) -> x)))
+ case (clazz @ ArrayClass(), value: Array[_]) => ArrayAnnotArg(value map (x => apply(clazz.getComponentType -> x)))
case (AnnotationClass(), value: jAnnotation) => NestedAnnotArg(JavaAnnotationProxy(value))
case _ => UnmappableAnnotArg
}
@@ -475,9 +475,9 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive
}
symbol match {
- case Any_== | Object_== => ScalaRunTime.inlinedEquals(objReceiver, objArg0)
- case Any_!= | Object_!= => !ScalaRunTime.inlinedEquals(objReceiver, objArg0)
- case Any_## | Object_## => ScalaRunTime.hash(objReceiver)
+ case Any_== | Object_== => objReceiver == objArg0
+ case Any_!= | Object_!= => objReceiver != objArg0
+ case Any_## | Object_## => objReceiver.##
case Any_equals => receiver.equals(objArg0)
case Any_hashCode => receiver.hashCode
case Any_toString => receiver.toString
@@ -613,7 +613,7 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive
loadBytes[String]("scala.reflect.ScalaSignature") match {
case Some(ssig) =>
info(s"unpickling Scala $clazz and $module, owner = ${clazz.owner}")
- val bytes = ssig.getBytes
+ val bytes = ssig.getBytes(java.nio.charset.StandardCharsets.UTF_8)
val len = ByteCodecs.decode(bytes)
assignAssociatedFile(clazz, module, jclazz)
unpickler.unpickle(bytes take len, 0, clazz, module, jclazz.getName)
@@ -622,7 +622,7 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive
loadBytes[Array[String]]("scala.reflect.ScalaLongSignature") match {
case Some(slsig) =>
info(s"unpickling Scala $clazz and $module with long Scala signature")
- val encoded = slsig flatMap (_.getBytes)
+ val encoded = slsig flatMap (_.getBytes(java.nio.charset.StandardCharsets.UTF_8))
val len = ByteCodecs.decode(encoded)
val decoded = encoded.take(len)
assignAssociatedFile(clazz, module, jclazz)
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
index 4630597668..d50debd7ee 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
@@ -377,6 +377,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
definitions.ElidableMethodClass
definitions.ImplicitNotFoundClass
definitions.ImplicitAmbiguousClass
+ definitions.JUnitTestClass
definitions.MigrationAnnotationClass
definitions.ScalaStrictFPAttr
definitions.SwitchClass
diff --git a/src/repl-jline/scala/tools/nsc/interpreter/jline/JLineReader.scala b/src/repl-jline/scala/tools/nsc/interpreter/jline/JLineReader.scala
index 1f2b0952e7..95964e18d9 100644
--- a/src/repl-jline/scala/tools/nsc/interpreter/jline/JLineReader.scala
+++ b/src/repl-jline/scala/tools/nsc/interpreter/jline/JLineReader.scala
@@ -11,10 +11,9 @@ import java.util.{Collection => JCollection, List => JList}
import _root_.jline.{console => jconsole}
import jline.console.ConsoleReader
-import jline.console.completer.{CompletionHandler, Completer}
+import jline.console.completer.{CandidateListCompletionHandler, Completer, CompletionHandler}
import jconsole.history.{History => JHistory}
-
import scala.tools.nsc.interpreter
import scala.tools.nsc.interpreter.{Completion, NoCompletion}
import scala.tools.nsc.interpreter.Completion.Candidates
@@ -133,32 +132,15 @@ private class JLineConsoleReader extends jconsole.ConsoleReader with interpreter
newCursor
}
}
+ getCompletionHandler match {
+ case clch: CandidateListCompletionHandler => clch.setPrintSpaceAfterFullCompletion(false)
+ }
completion match {
case NoCompletion => ()
case _ => this addCompleter completer
}
- // This is a workaround for https://github.com/jline/jline2/issues/208
- // and should not be necessary once we upgrade to JLine 2.13.1
- ///
- // Test by:
- // scala> {" ".char}<LEFT><TAB>
- //
- // And checking we don't get an extra } on the line.
- ///
- val handler = getCompletionHandler
- setCompletionHandler(new CompletionHandler {
- override def complete(consoleReader: ConsoleReader, list: JList[CharSequence], i: Int): Boolean = {
- try {
- handler.complete(consoleReader, list, i)
- } finally if (getCursorBuffer.cursor != getCursorBuffer.length()) {
- print(" ")
- getCursorBuffer.write(' ')
- backspace()
- }
- }
- })
setAutoprintThreshold(400) // max completion candidates without warning
}
}
diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala
index 893bde42ab..a42a12a6fc 100644
--- a/src/repl/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala
@@ -11,18 +11,17 @@ import PartialFunction.cond
import scala.language.implicitConversions
import scala.beans.BeanProperty
import scala.collection.mutable
-import scala.concurrent.{ Future, ExecutionContext }
-import scala.reflect.runtime.{ universe => ru }
-import scala.reflect.{ ClassTag, classTag }
-import scala.reflect.internal.util.{ BatchSourceFile, SourceFile }
-import scala.tools.util.PathResolverFactory
+import scala.concurrent.{ExecutionContext, Future}
+import scala.reflect.runtime.{universe => ru}
+import scala.reflect.{ClassTag, classTag}
+import scala.reflect.internal.util.{BatchSourceFile, SourceFile}
import scala.tools.nsc.io.AbstractFile
-import scala.tools.nsc.typechecker.{ TypeStrings, StructuredTypeStrings }
+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, ScriptContext, ScriptEngine, ScriptEngineFactory, ScriptException, CompiledScript, Compilable}
import java.net.URL
+import scala.tools.util.PathResolver
/** An interpreter for Scala code.
*
@@ -56,10 +55,11 @@ import java.net.URL
* @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")
@@ -91,7 +91,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
def compilerClasspath: Seq[java.net.URL] = (
if (isInitializeComplete) global.classPath.asURLs
- else PathResolverFactory.create(settings).resultAsURLs // the compiler's classpath
+ else new PathResolver(settings).resultAsURLs // the compiler's classpath
)
def settings = initialSettings
// Run the code body with the given boolean settings flipped to true.
@@ -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 6a75432ac6..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\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/PresentationCompilation.scala b/src/repl/scala/tools/nsc/interpreter/PresentationCompilation.scala
index e3dc72b717..b9a4054ffc 100644
--- a/src/repl/scala/tools/nsc/interpreter/PresentationCompilation.scala
+++ b/src/repl/scala/tools/nsc/interpreter/PresentationCompilation.scala
@@ -7,9 +7,7 @@ package scala.tools.nsc.interpreter
import scala.reflect.internal.util.RangePosition
import scala.reflect.io.AbstractFile
import scala.tools.nsc.backend.JavaPlatform
-import scala.tools.nsc.settings.ClassPathRepresentationType
-import scala.tools.nsc.util.ClassPath.DefaultJavaContext
-import scala.tools.nsc.util.{ClassPath, MergedClassPath, DirectoryClassPath}
+import scala.tools.nsc.util.ClassPath
import scala.tools.nsc.{interactive, Settings}
import scala.tools.nsc.reporters.StoreReporter
import scala.tools.nsc.classpath._
@@ -58,12 +56,8 @@ trait PresentationCompilation {
*/
def newPresentationCompiler(): interactive.Global = {
def mergedFlatClasspath = {
- val replOutClasspath = FlatClassPathFactory.newClassPath(replOutput.dir, settings)
- AggregateFlatClassPath(replOutClasspath :: global.platform.flatClassPath :: Nil)
- }
- def mergedRecursiveClasspath = {
- val replOutClasspath: DirectoryClassPath = new DirectoryClassPath(replOutput.dir, DefaultJavaContext)
- new MergedClassPath[AbstractFile](replOutClasspath :: global.platform.classPath :: Nil, DefaultJavaContext)
+ val replOutClasspath = ClassPathFactory.newClassPath(replOutput.dir, settings)
+ AggregateClassPath(replOutClasspath :: global.platform.classPath :: Nil)
}
def copySettings: Settings = {
val s = new Settings(_ => () /* ignores "bad option -nc" errors, etc */)
@@ -74,16 +68,9 @@ trait PresentationCompilation {
val storeReporter: StoreReporter = new StoreReporter
val interactiveGlobal = new interactive.Global(copySettings, storeReporter) { self =>
override lazy val platform: ThisPlatform = {
- if (settings.YclasspathImpl.value == ClassPathRepresentationType.Flat) {
- new JavaPlatform {
- val global: self.type = self
- override private[nsc] lazy val flatClassPath: FlatClassPath = mergedFlatClasspath
- }
- } else {
- new JavaPlatform {
- val global: self.type = self
- override def classPath: ClassPath[AbstractFile] = mergedRecursiveClasspath
- }
+ new JavaPlatform {
+ val global: self.type = self
+ override private[nsc] lazy val classPath: ClassPath = mergedFlatClasspath
}
}
}
diff --git a/src/repl/scala/tools/nsc/interpreter/ReplStrings.scala b/src/repl/scala/tools/nsc/interpreter/ReplStrings.scala
index 1664546cab..bf7508cb4e 100644
--- a/src/repl/scala/tools/nsc/interpreter/ReplStrings.scala
+++ b/src/repl/scala/tools/nsc/interpreter/ReplStrings.scala
@@ -11,13 +11,21 @@ import scala.reflect.internal.Chars
trait ReplStrings {
/** Convert a string into code that can recreate the string.
* This requires replacing all special characters by escape
- * codes. It does not add the surrounding " marks. */
+ * codes. It does not add the surrounding " marks.
+ */
def string2code(str: String): String = {
val res = new StringBuilder
for (c <- str) c match {
- case '"' | '\'' | '\\' => res += '\\' ; res += c
- case _ if c.isControl => res ++= Chars.char2uescape(c)
- case _ => res += c
+ case '"' => res ++= """\""""
+ case '\'' => res ++= """\'"""
+ case '\\' => res ++= """\\"""
+ case '\b' => res ++= """\b"""
+ case '\t' => res ++= """\t"""
+ case '\n' => res ++= """\n"""
+ case '\f' => res ++= """\f"""
+ case '\r' => res ++= """\r"""
+ case _ if c.isControl => res ++= Chars.char2uescape(c)
+ case _ => res += c
}
res.toString
}
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/base/CommentFactoryBase.scala b/src/scaladoc/scala/tools/nsc/doc/base/CommentFactoryBase.scala
index 8cd8a7ee09..d3b4bf8ff5 100644
--- a/src/scaladoc/scala/tools/nsc/doc/base/CommentFactoryBase.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/base/CommentFactoryBase.scala
@@ -295,7 +295,7 @@ trait CommentFactoryBase { this: MemberLookupBase =>
}
case line :: ls if (lastTagKey.isDefined) => {
- val newtags = if (!line.isEmpty) {
+ val newtags = if (!line.isEmpty || inCodeBlock) {
val key = lastTagKey.get
val value =
((tags get key): @unchecked) match {
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/src/scalap/scala/tools/scalap/Main.scala b/src/scalap/scala/tools/scalap/Main.scala
index 3d2bfd7251..6a37bbc270 100644
--- a/src/scalap/scala/tools/scalap/Main.scala
+++ b/src/scalap/scala/tools/scalap/Main.scala
@@ -8,17 +8,12 @@
package scala
package tools.scalap
-import java.io.{ PrintStream, OutputStreamWriter, ByteArrayOutputStream }
+import java.io.{ByteArrayOutputStream, OutputStreamWriter, PrintStream}
import scala.reflect.NameTransformer
import scala.tools.nsc.Settings
-import scala.tools.nsc.classpath.AggregateFlatClassPath
-import scala.tools.nsc.classpath.FlatClassPathFactory
-import scala.tools.nsc.io.AbstractFile
-import scala.tools.nsc.settings.ClassPathRepresentationType
-import scala.tools.nsc.util.ClassFileLookup
-import scala.tools.nsc.util.ClassPath.DefaultJavaContext
-import scala.tools.nsc.util.JavaClassPath
-import scala.tools.util.PathResolverFactory
+import scala.tools.nsc.classpath.{AggregateClassPath, ClassPathFactory}
+import scala.tools.nsc.util.ClassPath
+import scala.tools.util.PathResolver
import scalax.rules.scalasig._
/**The main object used to execute scalap on the command-line.
@@ -101,7 +96,7 @@ class Main {
/** Executes scalap with the given arguments and classpath for the
* class denoted by `classname`.
*/
- def process(args: Arguments, path: ClassFileLookup[AbstractFile])(classname: String): Unit = {
+ def process(args: Arguments, path: ClassPath)(classname: String): Unit = {
// find the classfile
val encName = classname match {
case "scala.AnyRef" => "java.lang.Object"
@@ -145,7 +140,6 @@ object Main extends Main {
val verbose = "-verbose"
val version = "-version"
- val classPathImplType = "-YclasspathImpl"
val disableFlatClassPathCaching = "-YdisableFlatCpCaching"
val logClassPath = "-Ylog-classpath"
}
@@ -183,7 +177,6 @@ object Main extends Main {
val settings = new Settings()
- arguments getArgument opts.classPathImplType foreach settings.YclasspathImpl.tryToSetFromPropertyValue
settings.YdisableFlatCpCaching.value = arguments contains opts.disableFlatClassPathCaching
settings.Ylogcp.value = arguments contains opts.logClassPath
@@ -205,21 +198,16 @@ object Main extends Main {
.withOption(opts.help)
.withOptionalArg(opts.classpath)
.withOptionalArg(opts.cp)
- // TODO three temporary, hidden options to be able to test different classpath representations
- .withOptionalArg(opts.classPathImplType)
+ // TODO two temporary, hidden options to be able to test different classpath representations
.withOption(opts.disableFlatClassPathCaching)
.withOption(opts.logClassPath)
.parse(args)
private def createClassPath(cpArg: Option[String], settings: Settings) = cpArg match {
- case Some(cp) => settings.YclasspathImpl.value match {
- case ClassPathRepresentationType.Flat =>
- AggregateFlatClassPath(new FlatClassPathFactory(settings).classesInExpandedPath(cp))
- case ClassPathRepresentationType.Recursive =>
- new JavaClassPath(DefaultJavaContext.classesInExpandedPath(cp), DefaultJavaContext)
- }
+ case Some(cp) =>
+ AggregateClassPath(new ClassPathFactory(settings).classesInExpandedPath(cp))
case _ =>
settings.classpath.value = "." // include '.' in the default classpath SI-6669
- PathResolverFactory.create(settings).result
+ new PathResolver(settings).result
}
}
diff --git a/test/disabled/presentation/akka/src/akka/actor/ActorRegistry.scala b/test/disabled/presentation/akka/src/akka/actor/ActorRegistry.scala
index 5d649fcd36..224775129b 100644
--- a/test/disabled/presentation/akka/src/akka/actor/ActorRegistry.scala
+++ b/test/disabled/presentation/akka/src/akka/actor/ActorRegistry.scala
@@ -342,7 +342,7 @@ class Index[K <: AnyRef, V <: AnyRef: ArrayTag] {
* if no matches it returns None
*/
def findValue(key: K)(f: (V) => Boolean): Option[V] = {
- import scala.collection.JavaConversions._
+ import scala.collection.convert.wrapAsScala._
val set = container get key
if (set ne null) set.iterator.find(f)
else None
@@ -352,7 +352,7 @@ class Index[K <: AnyRef, V <: AnyRef: ArrayTag] {
* Applies the supplied function to all keys and their values
*/
def foreach(fun: (K, V) => Unit) {
- import scala.collection.JavaConversions._
+ import scala.collection.convert.wrapAsScala._
container.entrySet foreach { (e) =>
e.getValue.foreach(fun(e.getKey, _))
}
diff --git a/test/disabled/presentation/akka/src/akka/actor/Scheduler.scala b/test/disabled/presentation/akka/src/akka/actor/Scheduler.scala
index 128584f3c5..ef540f2df3 100644
--- a/test/disabled/presentation/akka/src/akka/actor/Scheduler.scala
+++ b/test/disabled/presentation/akka/src/akka/actor/Scheduler.scala
@@ -15,8 +15,6 @@
*/
package akka.actor
-import scala.collection.JavaConversions
-
import java.util.concurrent._
import akka.event.EventHandler
diff --git a/test/disabled/presentation/akka/src/akka/japi/JavaAPI.scala b/test/disabled/presentation/akka/src/akka/japi/JavaAPI.scala
index f5c4ccdcaa..17ef3f7bb8 100644
--- a/test/disabled/presentation/akka/src/akka/japi/JavaAPI.scala
+++ b/test/disabled/presentation/akka/src/akka/japi/JavaAPI.scala
@@ -58,7 +58,7 @@ trait Creator[T] {
* Java API
*/
sealed abstract class Option[A] extends java.lang.Iterable[A] {
- import scala.collection.JavaConversions._
+ import scala.collection.convert.wrapAsScala._
def get: A
def isEmpty: Boolean
diff --git a/test/disabled/presentation/akka/src/akka/routing/Iterators.scala b/test/disabled/presentation/akka/src/akka/routing/Iterators.scala
index 315e7bea51..d110f2c269 100644
--- a/test/disabled/presentation/akka/src/akka/routing/Iterators.scala
+++ b/test/disabled/presentation/akka/src/akka/routing/Iterators.scala
@@ -5,7 +5,7 @@
package akka.routing
import akka.actor.ActorRef
-import scala.collection.JavaConversions._
+import scala.collection.convert.wrapAsScala._
import scala.collection.immutable.Seq
/**
diff --git a/test/disabled/presentation/akka/src/akka/routing/Listeners.scala b/test/disabled/presentation/akka/src/akka/routing/Listeners.scala
index 04f6c1259f..d8a537731d 100644
--- a/test/disabled/presentation/akka/src/akka/routing/Listeners.scala
+++ b/test/disabled/presentation/akka/src/akka/routing/Listeners.scala
@@ -6,7 +6,7 @@ package akka.routing
import akka.actor.{ Actor, ActorRef }
import java.util.concurrent.ConcurrentSkipListSet
-import scala.collection.JavaConversions._
+import scala.collection.convert.wrapAsScala._
sealed trait ListenerMessage
case class Listen(listener: ActorRef) extends ListenerMessage
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/scala-concurrent-tck.check b/test/files/jvm/scala-concurrent-tck.check
index 9aef07d1e5..8aec46e5d6 100644
--- a/test/files/jvm/scala-concurrent-tck.check
+++ b/test/files/jvm/scala-concurrent-tck.check
@@ -1 +1 @@
-warning: there were 73 deprecation warnings; re-run with -deprecation for details
+warning: there were 75 deprecation warnings; re-run with -deprecation for details
diff --git a/test/files/jvm/scala-concurrent-tck.scala b/test/files/jvm/scala-concurrent-tck.scala
index 8069028cf5..7197c1d853 100644
--- a/test/files/jvm/scala-concurrent-tck.scala
+++ b/test/files/jvm/scala-concurrent-tck.scala
@@ -90,6 +90,25 @@ trait FutureCallbacks extends TestBase {
promise.success(-1)
}
+ def stressTestNumberofCallbacks(): Unit = once {
+ done =>
+ val promise = Promise[Unit]
+ val otherPromise = Promise[Unit]
+ def attachMeaninglessCallbacksTo(f: Future[Any]): Unit = (1 to 1000).foreach(_ => f.onComplete(_ => ()))
+ attachMeaninglessCallbacksTo(promise.future)
+ val future = promise.future.flatMap { _ =>
+ attachMeaninglessCallbacksTo(otherPromise.future)
+ otherPromise.future
+ }
+ val numbers = new java.util.concurrent.ConcurrentHashMap[Int, Unit]()
+ (0 to 10000) foreach { x => numbers.put(x, ()) }
+ Future.sequence((0 to 10000) map { x => future.andThen({ case _ => numbers.remove(x) }) }) onComplete {
+ _ => done(numbers.isEmpty)
+ }
+ promise.success(())
+ otherPromise.success(())
+ }
+
testOnSuccess()
testOnSuccessWhenCompleted()
testOnSuccessWhenFailed()
@@ -100,6 +119,7 @@ trait FutureCallbacks extends TestBase {
//testOnFailureWhenSpecialThrowable(7, new InterruptedException)
testThatNestedCallbacksDoNotYieldStackOverflow()
testOnFailureWhenTimeoutException()
+ stressTestNumberofCallbacks()
}
@@ -283,6 +303,16 @@ def testTransformFailure(): Unit = once {
g onFailure { case t => done(t.getMessage() == "expected") }
}
+ def testFlatMapDelayed(): Unit = once {
+ done =>
+ val f = Future { 5 }
+ val p = Promise[Int]
+ val g = f flatMap { _ => p.future }
+ g onSuccess { case x => done(x == 10) }
+ g onFailure { case _ => done(false) }
+ p.success(10)
+ }
+
def testFilterSuccess(): Unit = once {
done =>
val f = Future { 4 }
@@ -458,6 +488,7 @@ def testTransformFailure(): Unit = once {
testMapFailure()
testFlatMapSuccess()
testFlatMapFailure()
+ testFlatMapDelayed()
testFilterSuccess()
testFilterFailure()
testCollectSuccess()
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/nowarnDefaultJunitMethods.check b/test/files/neg/nowarnDefaultJunitMethods.check
new file mode 100644
index 0000000000..7efdcc299a
--- /dev/null
+++ b/test/files/neg/nowarnDefaultJunitMethods.check
@@ -0,0 +1,6 @@
+C_1.scala:2: warning: JUnit tests in traits that are compiled as default methods are not executed by JUnit 4. JUnit 5 will fix this issue.
+ @org.junit.Test def foo = 0
+ ^
+error: No warnings can be incurred under -Xfatal-warnings.
+one warning found
+one error found
diff --git a/test/files/neg/nowarnDefaultJunitMethods.flags b/test/files/neg/nowarnDefaultJunitMethods.flags
new file mode 100644
index 0000000000..85d8eb2ba2
--- /dev/null
+++ b/test/files/neg/nowarnDefaultJunitMethods.flags
@@ -0,0 +1 @@
+-Xfatal-warnings
diff --git a/test/files/neg/nowarnDefaultJunitMethods/C_1.scala b/test/files/neg/nowarnDefaultJunitMethods/C_1.scala
new file mode 100644
index 0000000000..e2565a48bc
--- /dev/null
+++ b/test/files/neg/nowarnDefaultJunitMethods/C_1.scala
@@ -0,0 +1,5 @@
+trait T {
+ @org.junit.Test def foo = 0
+}
+
+class C extends T
diff --git a/test/files/neg/nowarnDefaultJunitMethods/Test.java b/test/files/neg/nowarnDefaultJunitMethods/Test.java
new file mode 100644
index 0000000000..e8d64c2cc8
--- /dev/null
+++ b/test/files/neg/nowarnDefaultJunitMethods/Test.java
@@ -0,0 +1,3 @@
+package org.junit;
+
+public @interface Test { }
diff --git a/test/files/neg/saferJavaConversions.scala b/test/files/neg/saferJavaConversions.scala
index f0611204e6..b70a918404 100644
--- a/test/files/neg/saferJavaConversions.scala
+++ b/test/files/neg/saferJavaConversions.scala
@@ -3,17 +3,17 @@ case class Foo(s: String)
object Test {
def f1 = {
- import scala.collection.JavaConversions._
+ import scala.collection.convert.ImplicitConversions._
val map: Map[Foo, String] = Map(Foo("a") -> "a", Foo("b") -> "b")
val v = map.get("a") // should be a type error, actually returns null
}
def f2 = {
- import scala.collection.convert.wrapAsScala._
+ import scala.collection.convert.ImplicitConversionsToScala._
val map: Map[Foo, String] = Map(Foo("a") -> "a", Foo("b") -> "b")
val v = map.get("a") // now this is a type error
}
def f3 = {
- import scala.collection.convert.wrapAsJava._
+ import scala.collection.convert.ImplicitConversionsToJava._
val map: Map[Foo, String] = Map(Foo("a") -> "a", Foo("b") -> "b")
val v = map.get("a")
}
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/t4749.check b/test/files/neg/t4749.check
index 3539140954..6bd2550097 100644
--- a/test/files/neg/t4749.check
+++ b/test/files/neg/t4749.check
@@ -26,7 +26,7 @@ t4749.scala:26: warning: Fail6 has a main method with parameter type Array[Strin
object Fail6 {
^
t4749.scala:42: warning: Win3 has a main method with parameter type Array[String], but bippy.Win3 will not be a runnable program.
- Reason: main method must have exact signature (Array[String])Unit
+ Reason: main methods cannot refer to type parameters or abstract types.
object Win3 extends WinBippy[Unit] { }
^
error: No warnings can be incurred under -Xfatal-warnings.
diff --git a/test/files/neg/t5148.check b/test/files/neg/t5148.check
deleted file mode 100644
index 1f58c235ce..0000000000
--- a/test/files/neg/t5148.check
+++ /dev/null
@@ -1,16 +0,0 @@
-error: missing or invalid dependency detected while loading class file 'Imports.class'.
-Could not access term memberHandlers in class scala.tools.nsc.interpreter.IMain,
-because it (or its dependencies) are missing. Check your build definition for
-missing or conflicting dependencies. (Re-run with `-Ylog-classpath` to see the problematic classpath.)
-A full rebuild may help if 'Imports.class' was compiled against an incompatible version of scala.tools.nsc.interpreter.IMain.
-error: missing or invalid dependency detected while loading class file 'Imports.class'.
-Could not access type Wrapper in class scala.tools.nsc.interpreter.IMain.Request,
-because it (or its dependencies) are missing. Check your build definition for
-missing or conflicting dependencies. (Re-run with `-Ylog-classpath` to see the problematic classpath.)
-A full rebuild may help if 'Imports.class' was compiled against an incompatible version of scala.tools.nsc.interpreter.IMain.Request.
-error: missing or invalid dependency detected while loading class file 'Imports.class'.
-Could not access type Request in class scala.tools.nsc.interpreter.IMain,
-because it (or its dependencies) are missing. Check your build definition for
-missing or conflicting dependencies. (Re-run with `-Ylog-classpath` to see the problematic classpath.)
-A full rebuild may help if 'Imports.class' was compiled against an incompatible version of scala.tools.nsc.interpreter.IMain.
-three errors found
diff --git a/test/files/neg/t5580b.scala b/test/files/neg/t5580b.scala
index 2161da4584..98b493e803 100644
--- a/test/files/neg/t5580b.scala
+++ b/test/files/neg/t5580b.scala
@@ -1,5 +1,5 @@
import scala.collection.mutable.WeakHashMap
-import scala.collection.JavaConversions._
+import scala.collection.JavaConverters._
class bar { }
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/neg/t9684.check b/test/files/neg/t9684.check
new file mode 100644
index 0000000000..833ca3341a
--- /dev/null
+++ b/test/files/neg/t9684.check
@@ -0,0 +1,9 @@
+t9684.scala:6: warning: object JavaConversions in package collection is deprecated: Use JavaConverters
+ null.asInstanceOf[java.util.List[Int]] : Buffer[Int]
+ ^
+t9684.scala:8: warning: object JavaConversions in package collection is deprecated: Use JavaConverters
+ null.asInstanceOf[Iterable[Int]] : java.util.Collection[Int]
+ ^
+error: No warnings can be incurred under -Xfatal-warnings.
+two warnings found
+one error found
diff --git a/test/files/neg/t9684.flags b/test/files/neg/t9684.flags
new file mode 100644
index 0000000000..c6bfaf1f64
--- /dev/null
+++ b/test/files/neg/t9684.flags
@@ -0,0 +1 @@
+-deprecation -Xfatal-warnings
diff --git a/test/files/neg/t9684.scala b/test/files/neg/t9684.scala
new file mode 100644
index 0000000000..f7ece269e6
--- /dev/null
+++ b/test/files/neg/t9684.scala
@@ -0,0 +1,9 @@
+
+import scala.collection.JavaConversions._
+import scala.collection.mutable.Buffer
+
+trait Test {
+ null.asInstanceOf[java.util.List[Int]] : Buffer[Int]
+
+ null.asInstanceOf[Iterable[Int]] : java.util.Collection[Int]
+}
diff --git a/test/files/neg/t9684b.check b/test/files/neg/t9684b.check
new file mode 100644
index 0000000000..5f328abd43
--- /dev/null
+++ b/test/files/neg/t9684b.check
@@ -0,0 +1,7 @@
+t9684b.scala:6: error: reference to asScalaIterator is ambiguous;
+it is imported twice in the same scope by
+import scala.collection.JavaConversions._
+and import scala.collection.JavaConverters._
+ asScalaIterator(null) // fails: asScalaIterator is imported twice.
+ ^
+one error found
diff --git a/test/files/neg/t9684b.scala b/test/files/neg/t9684b.scala
new file mode 100644
index 0000000000..010e9d1b5d
--- /dev/null
+++ b/test/files/neg/t9684b.scala
@@ -0,0 +1,14 @@
+trait T1 {
+ import scala.collection.JavaConverters._
+ import scala.collection.JavaConversions._
+
+ null.asInstanceOf[java.util.Iterator[String]]: Iterator[String] // works
+ asScalaIterator(null) // fails: asScalaIterator is imported twice.
+}
+
+trait T2 {
+ import scala.collection.JavaConversions.asScalaIterator
+
+ null.asInstanceOf[java.util.Iterator[String]]: Iterator[String] // works
+ asScalaIterator(null) // works
+}
diff --git a/test/files/pos/arrays2.scala b/test/files/pos/arrays2.scala
index 795c486e37..b770d21b8a 100644
--- a/test/files/pos/arrays2.scala
+++ b/test/files/pos/arrays2.scala
@@ -17,7 +17,7 @@ object arrays4 {
// #2461
object arrays3 {
- import scala.collection.JavaConversions._
+ import collection.convert.ImplicitConversions._
def apply[X](xs : X*) : java.util.List[X] = java.util.Arrays.asList(xs: _*)
}
diff --git a/test/files/pos/constant-warning.check b/test/files/pos/constant-warning.check
new file mode 100644
index 0000000000..f7df2165d1
--- /dev/null
+++ b/test/files/pos/constant-warning.check
@@ -0,0 +1,4 @@
+constant-warning.scala:2: warning: Evaluation of a constant expression results in an arithmetic error: / by zero
+ val fails = 1 + 2 / (3 - 2 - 1)
+ ^
+one warning found
diff --git a/test/files/pos/constant-warning.flags b/test/files/pos/constant-warning.flags
new file mode 100644
index 0000000000..d00cbbe77b
--- /dev/null
+++ b/test/files/pos/constant-warning.flags
@@ -0,0 +1 @@
+-Xlint:constant
diff --git a/test/files/pos/constant-warning.scala b/test/files/pos/constant-warning.scala
new file mode 100644
index 0000000000..c8ca8823e7
--- /dev/null
+++ b/test/files/pos/constant-warning.scala
@@ -0,0 +1,3 @@
+object Test {
+ val fails = 1 + 2 / (3 - 2 - 1)
+}
diff --git a/test/files/pos/javaConversions-2.10-ambiguity.scala b/test/files/pos/javaConversions-2.10-ambiguity.scala
index c4aad6cbfc..b08568f475 100644
--- a/test/files/pos/javaConversions-2.10-ambiguity.scala
+++ b/test/files/pos/javaConversions-2.10-ambiguity.scala
@@ -1,5 +1,5 @@
-import collection.{JavaConversions, mutable, concurrent}
-import JavaConversions._
+import collection.{mutable, concurrent}
+import collection.convert.ImplicitConversionsToScala._
import java.util.concurrent.{ConcurrentHashMap => CHM}
object Bar {
diff --git a/test/files/pos/javaConversions-2.10-regression.scala b/test/files/pos/javaConversions-2.10-regression.scala
index 7c7ff03b55..8d84c92b61 100644
--- a/test/files/pos/javaConversions-2.10-regression.scala
+++ b/test/files/pos/javaConversions-2.10-regression.scala
@@ -1,10 +1,10 @@
-import collection.{JavaConversions, mutable, concurrent}
-import JavaConversions._
+import collection.{convert, mutable, concurrent, JavaConverters}
+import convert.ImplicitConversionsToScala._
import java.util.concurrent.{ConcurrentHashMap => CHM}
object Foo {
def buildCache2_9_simple[K <: AnyRef, V <: AnyRef]: concurrent.Map[K, V] =
- mapAsScalaConcurrentMap(new CHM())
+ JavaConverters.mapAsScalaConcurrentMap(new CHM())
def buildCache2_9_implicit[K <: AnyRef, V <: AnyRef]: concurrent.Map[K, V] =
new CHM[K, V]()
diff --git a/test/files/pos/t2293.scala b/test/files/pos/t2293.scala
index 65f717f851..baa44552c9 100644
--- a/test/files/pos/t2293.scala
+++ b/test/files/pos/t2293.scala
@@ -1,5 +1,5 @@
-import scala.collection.JavaConversions._
+import scala.collection.convert.ImplicitConversionsToJava._
object Test {
val m: java.util.Map[String,String] = collection.mutable.Map("1"->"2")
-} \ No newline at end of file
+}
diff --git a/test/files/pos/t2956/t2956.scala b/test/files/pos/t2956/t2956.scala
index eb6e817465..9b6ae8098f 100644
--- a/test/files/pos/t2956/t2956.scala
+++ b/test/files/pos/t2956/t2956.scala
@@ -1,7 +1,7 @@
-import scala.collection.JavaConversions._
+import scala.collection.convert.ImplicitConversionsToScala._
class Outer {
protected class Inner extends BeanDefinitionVisitor {
protected def visitMap(mapVal: Map[_, _]): Unit = ()
}
-} \ No newline at end of file
+}
diff --git a/test/files/pos/t3688.scala b/test/files/pos/t3688.scala
index d15e9d1a84..58464332d1 100644
--- a/test/files/pos/t3688.scala
+++ b/test/files/pos/t3688.scala
@@ -1,5 +1,5 @@
import collection.mutable
-import collection.JavaConversions._
+import collection.convert.ImplicitConversionsToJava._
import java.{util => ju}
object Test {
@@ -11,4 +11,4 @@ object Test {
object Test2 {
def m[P <% ju.List[Int]](l: P) = 1
m(List(1)) // bug: should compile
-} \ No newline at end of file
+}
diff --git a/test/files/neg/t5148.scala b/test/files/pos/t5148.scala
index fca64e57df..fca64e57df 100644
--- a/test/files/neg/t5148.scala
+++ b/test/files/pos/t5148.scala
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/t5644/BoxesRunTime.java b/test/files/pos/t5644/BoxesRunTime.java
index 74c4c6b4b9..2b931519aa 100644
--- a/test/files/pos/t5644/BoxesRunTime.java
+++ b/test/files/pos/t5644/BoxesRunTime.java
@@ -267,10 +267,6 @@ public final class BoxesRunTime
else if (n instanceof java.lang.Float) return hashFromFloat((java.lang.Float)n);
else return n.hashCode();
}
- public static int hashFromObject(Object a) {
- if (a instanceof Number) return hashFromNumber((Number)a);
- else return a.hashCode();
- }
private static int unboxCharOrInt(Object arg1, int code) {
if (code == CHAR)
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/t9397.scala b/test/files/pos/t9397.scala
new file mode 100644
index 0000000000..3dbc6591d3
--- /dev/null
+++ b/test/files/pos/t9397.scala
@@ -0,0 +1,12 @@
+package foo.scala
+
+import scala.reflect.runtime.universe._
+
+object Foo {
+
+ def bar[T: TypeTag]() {
+ }
+
+ import foo._
+ bar[String]()
+}
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/presentation/ide-bug-1000531/src/CrashOnLoad.scala b/test/files/presentation/ide-bug-1000531/src/CrashOnLoad.scala
index 3f59282083..25e0a9580f 100644
--- a/test/files/presentation/ide-bug-1000531/src/CrashOnLoad.scala
+++ b/test/files/presentation/ide-bug-1000531/src/CrashOnLoad.scala
@@ -1,6 +1,6 @@
/** When this files is opened within the IDE, a typing error is reported. */
class A[B] extends TestIterable[B] {
- import scala.collection.JavaConversions._
+ import collection.convert.ImplicitConversionsToScala._
def iterator: other.TestIterator[Nothing] = ???
iterator./*!*/
diff --git a/test/files/run/concurrent-map-conversions.scala b/test/files/run/concurrent-map-conversions.scala
index d23d5bbbe4..1179764e37 100644
--- a/test/files/run/concurrent-map-conversions.scala
+++ b/test/files/run/concurrent-map-conversions.scala
@@ -1,14 +1,5 @@
-
-
-
-
-object Test {
-
- def main(args: Array[String]) {
- testConversions()
- testConverters()
- }
+object Test extends App {
def needPackageConcurrentMap(map: collection.concurrent.Map[Int, Int]) {
}
@@ -16,7 +7,7 @@ object Test {
}
def testConversions() {
- import collection.JavaConversions._
+ import collection.convert.ImplicitConversions._
val skiplist = new java.util.concurrent.ConcurrentSkipListMap[Int, Int]
val ctrie = new collection.concurrent.TrieMap[Int, Int]
@@ -33,4 +24,6 @@ object Test {
needJavaConcurrent(ctrie.asJava)
}
+ testConversions()
+ testConverters()
}
diff --git a/test/files/run/equality.scala b/test/files/run/equality.scala
index ff59898821..2af73691d8 100644
--- a/test/files/run/equality.scala
+++ b/test/files/run/equality.scala
@@ -1,7 +1,7 @@
// a quickly assembled test of equality. Needs work.
object Test
{
- import scala.runtime.ScalaRunTime.hash
+ def hash(x: Any): Int = x.## // forces upcast to Any
def makeFromInt(x: Int) = List(
x.toByte, x.toShort, x.toInt, x.toLong, x.toFloat, x.toDouble, BigInt(x), BigDecimal(x)
diff --git a/test/files/run/hashCodeBoxesRunTime.scala b/test/files/run/hashCodeStatics.scala
index ba1a30f5fb..bff62cce18 100644
--- a/test/files/run/hashCodeBoxesRunTime.scala
+++ b/test/files/run/hashCodeStatics.scala
@@ -1,23 +1,23 @@
-// This only tests direct access to the methods in BoxesRunTime,
+// This only tests direct access to the methods in Statics,
// not the whole scheme.
object Test
{
import java.{ lang => jl }
- import scala.runtime.BoxesRunTime.{ hashFromNumber, hashFromObject }
+ import scala.runtime.Statics.anyHash
def allSame[T](xs: List[T]) = assert(xs.distinct.size == 1, "failed: " + xs)
def mkNumbers(x: Int): List[Number] =
List(x.toByte, x.toShort, x, x.toLong, x.toFloat, x.toDouble)
- def testLDF(x: Long) = allSame(List[Number](x, x.toDouble, x.toFloat) map hashFromNumber)
+ def testLDF(x: Long) = allSame(List[Number](x, x.toDouble, x.toFloat) map anyHash)
def main(args: Array[String]): Unit = {
List(Byte.MinValue, -1, 0, 1, Byte.MaxValue) foreach { n =>
- val hashes = mkNumbers(n) map hashFromNumber
+ val hashes = mkNumbers(n) map anyHash
allSame(hashes)
if (n >= 0) {
- val charCode = hashFromObject(n.toChar: Character)
+ val charCode = anyHash(n.toChar: Character)
assert(charCode == hashes.head)
}
}
diff --git a/test/files/run/map_java_conversions.scala b/test/files/run/map_java_conversions.scala
index c007b3e0eb..e287b0eb09 100644
--- a/test/files/run/map_java_conversions.scala
+++ b/test/files/run/map_java_conversions.scala
@@ -1,20 +1,16 @@
-
-
-
-
+import collection.convert.ImplicitConversionsToScala._
+import collection.JavaConverters._
object Test {
def main(args: Array[String]) {
- import collection.JavaConversions._
-
test(new java.util.HashMap[String, String])
test(new java.util.Properties)
testConcMap
}
def testConcMap {
- import collection.JavaConversions._
+ import collection.convert.ImplicitConversionsToScala._
val concMap = new java.util.concurrent.ConcurrentHashMap[String, String]
@@ -50,7 +46,6 @@ object Test {
for (i <- 0 until 10) m += (("key" + i, "value" + i))
for ((k, v) <- m) assert(k.startsWith("key"))
}
-
}
diff --git a/test/files/run/mixin-signatures.check b/test/files/run/mixin-signatures.check
index 77bff79ac8..9961992e2d 100644
--- a/test/files/run/mixin-signatures.check
+++ b/test/files/run/mixin-signatures.check
@@ -1,19 +1,23 @@
class Test$bar1$ {
- public java.lang.String Test$bar1$.f(java.lang.Object)
+ public default java.lang.String Foo1.f(java.lang.Object)
+ generic: public default java.lang.String Foo1.f(T)
public java.lang.Object Test$bar1$.f(java.lang.Object) <bridge> <synthetic>
public java.lang.String Test$bar1$.g(java.lang.String)
public java.lang.Object Test$bar1$.g(java.lang.Object) <bridge> <synthetic>
public java.lang.String Test$bar1$.g(java.lang.Object) <bridge> <synthetic>
- public java.lang.Object Test$bar1$.h(java.lang.Object)
+ public default java.lang.Object Base.h(java.lang.Object)
+ generic: public default R Base.h(T)
}
class Test$bar2$ {
- public java.lang.Object Test$bar2$.f(java.lang.String)
+ public default java.lang.Object Foo2.f(java.lang.String)
+ generic: public default R Foo2.f(java.lang.String)
public java.lang.Object Test$bar2$.f(java.lang.Object) <bridge> <synthetic>
public java.lang.String Test$bar2$.g(java.lang.String)
public java.lang.Object Test$bar2$.g(java.lang.Object) <bridge> <synthetic>
public java.lang.Object Test$bar2$.g(java.lang.String) <bridge> <synthetic>
- public java.lang.Object Test$bar2$.h(java.lang.Object)
+ public default java.lang.Object Base.h(java.lang.Object)
+ generic: public default R Base.h(T)
}
class Test$bar3$ {
@@ -23,7 +27,8 @@ class Test$bar3$ {
public java.lang.String Test$bar3$.g(java.lang.String)
public java.lang.Object Test$bar3$.g(java.lang.Object) <bridge> <synthetic>
public java.lang.String Test$bar3$.g(java.lang.Object) <bridge> <synthetic>
- public java.lang.Object Foo3.h(java.lang.Object)
+ public default java.lang.Object Base.h(java.lang.Object)
+ generic: public default R Base.h(T)
}
class Test$bar4$ {
@@ -33,7 +38,8 @@ class Test$bar4$ {
public java.lang.String Test$bar4$.g(java.lang.String)
public java.lang.Object Test$bar4$.g(java.lang.Object) <bridge> <synthetic>
public java.lang.Object Test$bar4$.g(java.lang.String) <bridge> <synthetic>
- public java.lang.Object Foo4.h(java.lang.Object)
+ public default java.lang.Object Base.h(java.lang.Object)
+ generic: public default R Base.h(T)
}
class Test$bar5$ {
@@ -45,7 +51,8 @@ class Test$bar5$ {
public java.lang.Object Test$bar5$.g(java.lang.Object) <bridge> <synthetic>
public java.lang.Object Test$bar5$.g(java.lang.String) <bridge> <synthetic>
public java.lang.String Test$bar5$.g(java.lang.Object) <bridge> <synthetic>
- public java.lang.Object Test$bar5$.h(java.lang.Object)
+ public default java.lang.Object Base.h(java.lang.Object)
+ generic: public default R Base.h(T)
}
interface Foo1 {
diff --git a/test/files/run/noInlineUnknownIndy/Test.scala b/test/files/run/noInlineUnknownIndy/Test.scala
index 16d8126543..8d2d20a3cd 100644
--- a/test/files/run/noInlineUnknownIndy/Test.scala
+++ b/test/files/run/noInlineUnknownIndy/Test.scala
@@ -1,6 +1,6 @@
import java.io.File
-import scala.collection.convert.decorateAsScala._
+import scala.collection.JavaConverters._
import scala.tools.asm.tree.{ClassNode, InvokeDynamicInsnNode}
import scala.tools.asm.{Handle, Opcodes}
import scala.tools.partest.BytecodeTest.modifyClassFile
diff --git a/test/files/run/reify_printf.scala b/test/files/run/reify_printf.scala
index c4ade79837..099a353e89 100644
--- a/test/files/run/reify_printf.scala
+++ b/test/files/run/reify_printf.scala
@@ -6,7 +6,6 @@ import scala.tools.reflect.ToolBox
import scala.reflect.api._
import scala.reflect.api.Trees
import scala.reflect.internal.Types
-import scala.util.matching.Regex
object Test extends App {
//val output = new ByteArrayOutputStream()
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-no-uescape.check b/test/files/run/repl-no-uescape.check
new file mode 100644
index 0000000000..01eeafaa70
--- /dev/null
+++ b/test/files/run/repl-no-uescape.check
@@ -0,0 +1,5 @@
+
+scala> object A
+defined object A
+
+scala> :quit
diff --git a/test/files/run/repl-no-uescape.scala b/test/files/run/repl-no-uescape.scala
new file mode 100644
index 0000000000..1865109ebf
--- /dev/null
+++ b/test/files/run/repl-no-uescape.scala
@@ -0,0 +1,31 @@
+import scala.tools.partest.ReplTest
+import scala.tools.nsc.Settings
+
+/*
+scala> object A
+<console>:10: error: invalid escape character
++ "defined object " + "A" + "\u000A"
+
+Under -Dscala.color=true control chars are common
+ $eval.this.$print = {
+ $line2.$read.$iw.$iw;
+ "\033[1m\033[34mres1\033[0m: \033[1m\033[32mInt\033[0m = ".+(scala.runtime.ScalaRunTime.replStringOf($line2.$read.$iw.$iw.res1, 1000))
+ };
+
+$ skala -Dscala.color=true -Xno-uescape
+Welcome to Scala 2.11.9-20160323-163638-1fcfdd8c8b (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_60).
+Type in expressions for evaluation. Or try :help.
+
+scala> 42
+<console>:10: error: invalid escape character
+ + "\u001B[1m\u001B[34mres0\u001B[0m: \u001B[1m\u001B[32mInt\u001B[0m = " + scala.runtime.ScalaRunTime.replStringOf(res0, 1000)
+ */
+object Test extends ReplTest {
+ override def transformSettings(settings: Settings): Settings = {
+ settings.nouescape.value = true
+ settings
+ }
+ def code = """
+object A
+ """
+}
diff --git a/test/files/run/repl-paste-6.check b/test/files/run/repl-paste-6.check
new file mode 100755
index 0000000000..efcea9274f
--- /dev/null
+++ b/test/files/run/repl-paste-6.check
@@ -0,0 +1,17 @@
+
+scala> :paste < EOF
+// Entering paste mode (EOF to finish)
+
+case class C(i: Int)
+val c = C(42)
+EOF
+
+// Exiting paste mode, now interpreting.
+
+defined class C
+c: C = C(42)
+
+scala> val d: C = c // shew
+d: C = C(42)
+
+scala> :quit
diff --git a/test/files/run/repl-paste-6.scala b/test/files/run/repl-paste-6.scala
new file mode 100644
index 0000000000..8040d24f8a
--- /dev/null
+++ b/test/files/run/repl-paste-6.scala
@@ -0,0 +1,23 @@
+
+import scala.tools.partest.ReplTest
+import scala.tools.nsc.Settings
+
+
+/*
+ * Add // show to witness:
+ * val $line3$read: $line3.$read.INSTANCE.type = $line3.$read.INSTANCE;
+ */
+object Test extends ReplTest {
+ override def transformSettings(settings: Settings): Settings = {
+ settings.Yreplclassbased.value = true
+ settings
+ }
+ def code =
+ """
+:paste < EOF
+case class C(i: Int)
+val c = C(42)
+EOF
+val d: C = c // shew
+ """
+}
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/t2106.check b/test/files/run/t2106.check
index b19165824b..c8ebe575f0 100644
--- a/test/files/run/t2106.check
+++ b/test/files/run/t2106.check
@@ -1,5 +1,5 @@
t2106.scala:7: warning: A::foo()Ljava/lang/Object; is annotated @inline but could not be inlined:
-The callee A::foo()Ljava/lang/Object; contains the instruction INVOKEVIRTUAL java/lang/Object.clone ()Ljava/lang/Object;
+The callee A::foo()Ljava/lang/Object; contains the instruction INVOKEVIRTUAL A.clone ()Ljava/lang/Object;
that would cause an IllegalAccessError when inlined into class Test$.
def main(args: Array[String]): Unit = x.foo
^
diff --git a/test/files/run/t2250.scala b/test/files/run/t2250.scala
index 1ed333792a..f87b76d4d7 100644
--- a/test/files/run/t2250.scala
+++ b/test/files/run/t2250.scala
@@ -6,7 +6,7 @@ object Test {
// we'll say rather unlikely a.sameElements(b) unless
// they are pointing to the same array
- import scala.collection.JavaConversions._
+ import scala.collection.convert.ImplicitConversionsToScala._
assert(a sameElements b)
}
}
diff --git a/test/files/run/t2813.2.scala b/test/files/run/t2813.2.scala
index f41f6451f4..f26753600d 100644
--- a/test/files/run/t2813.2.scala
+++ b/test/files/run/t2813.2.scala
@@ -1,5 +1,5 @@
import java.util.LinkedList
-import collection.JavaConversions._
+import collection.convert.ImplicitConversions._
object Test extends App {
def assertListEquals[A](expected: List[A], actual: Seq[A]) {
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/t5652.check b/test/files/run/t5652.check
index 326b22f9dd..a0fb6fe9b4 100644
--- a/test/files/run/t5652.check
+++ b/test/files/run/t5652.check
@@ -4,5 +4,4 @@ public default void T1.$init$()
public final int A1.A1$$g$2()
public int A1.f1()
public final int A2.A2$$g$1()
-public int A2.f0()
public int A2.f2()
diff --git a/test/files/run/t5880.scala b/test/files/run/t5880.scala
index f88df90160..284ba03ff6 100644
--- a/test/files/run/t5880.scala
+++ b/test/files/run/t5880.scala
@@ -1,8 +1,5 @@
-
-import scala.collection.JavaConversions._
-
-
+import scala.collection.convert.ImplicitConversionsToJava._
object Test {
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/t6502.scala b/test/files/run/t6502.scala
index dffb0e2f98..cb2b3ff449 100644
--- a/test/files/run/t6502.scala
+++ b/test/files/run/t6502.scala
@@ -1,6 +1,5 @@
import scala.tools.nsc.Settings
import scala.tools.nsc.interpreter.{ ILoop, replProps }
-import scala.tools.nsc.settings.ClassPathRepresentationType
import scala.tools.partest._
object Test extends StoreReporterDirectTest {
@@ -14,14 +13,6 @@ object Test extends StoreReporterDirectTest {
compileString(newCompiler("-cp", classpath, "-d", s"${testOutput.path}/$jarFileName"))(code)
}
- var classPathKind: String = ""
-
- override def settings = {
- val settings = new Settings
- settings.YclasspathImpl.value = classPathKind
- settings
- }
-
def app1 = """
package test
@@ -155,7 +146,7 @@ object Test extends StoreReporterDirectTest {
assert(output.contains("created test6.Z"), output)
}
- def testAll(): Unit = {
+ def show(): Unit = {
test1()
test2()
test3()
@@ -163,11 +154,4 @@ object Test extends StoreReporterDirectTest {
test5()
test6()
}
-
- def show(): Unit = {
- classPathKind = ClassPathRepresentationType.Flat
- testAll()
- classPathKind = ClassPathRepresentationType.Recursive
- testAll()
- }
}
diff --git a/test/files/run/t6554.scala b/test/files/run/t6554.scala
index 5d29d16666..eed139fea6 100644
--- a/test/files/run/t6554.scala
+++ b/test/files/run/t6554.scala
@@ -1,8 +1,14 @@
-trait Foo[A] {
+trait T1[A] {
def minBy[B](b: B): A = ???
}
-
-class Bar extends Foo[Int]
+
+// The second trait is needed to make sure there's a forwarder generated in Bar.
+// otherwise Bar.minBy is just the inherited default method from T1.
+trait T2[A] { self: T1[A] =>
+ override def minBy[B](b: B): A = ???
+}
+
+class Bar extends T1[Int] with T2[Int]
object Test extends App {
val sigs = classOf[Bar].getDeclaredMethods.map(m => s"${m.toString} / ${m.toGenericString}").sorted
diff --git a/test/files/run/t7269.scala b/test/files/run/t7269.scala
index d22e57dfee..1102d49ecb 100644
--- a/test/files/run/t7269.scala
+++ b/test/files/run/t7269.scala
@@ -1,4 +1,4 @@
-import scala.collection.JavaConversions._
+import scala.collection.convert.ImplicitConversionsToScala._
import scala.collection.mutable
object Test extends App {
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/t7932.check b/test/files/run/t7932.check
index 3f0a0c4f62..a2ad84cd46 100644
--- a/test/files/run/t7932.check
+++ b/test/files/run/t7932.check
@@ -1,3 +1,6 @@
-warning: there was one feature warning; re-run with -feature for details
public Category<?> C.category()
public Category<scala.Tuple2> C.category1()
+public default Category<java.lang.Object> M1.category()
+public default Category<scala.Tuple2> M1.category1()
+public default Category<java.lang.Object> M2.category()
+public default Category<scala.Tuple2> M2.category1()
diff --git a/test/files/run/t7932.scala b/test/files/run/t7932.scala
index 8743abff88..e6bdbf2417 100644
--- a/test/files/run/t7932.scala
+++ b/test/files/run/t7932.scala
@@ -1,11 +1,28 @@
+import scala.language.higherKinds
+
class Category[M[_, _]]
-trait M[F] {
+
+trait M1[F] {
type X[a, b] = F
def category: Category[X] = null
def category1: Category[Tuple2] = null
}
-abstract class C extends M[Float]
+
+// The second trait is needed to make sure there's a forwarder generated in C.
+// otherwise the trait methods are just the inherited default methods from M1.
+trait M2[F] { self: M1[F] =>
+ override def category: Category[X] = null
+ override def category1: Category[Tuple2] = null
+}
+
+abstract class C extends M1[Float] with M2[Float]
+
object Test extends App {
- val ms = classOf[C].getMethods.filter(_.getName.startsWith("category"))
- println(ms.map(_.toGenericString).sorted.mkString("\n"))
+ def t(c: Class[_]) = {
+ val ms = c.getMethods.filter(_.getName.startsWith("category"))
+ println(ms.map(_.toGenericString).sorted.mkString("\n"))
+ }
+ t(classOf[C])
+ t(classOf[M1[_]])
+ t(classOf[M2[_]])
}
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/t7974/Test.scala b/test/files/run/t7974/Test.scala
index 296ec32ee2..53ec71bc2b 100644
--- a/test/files/run/t7974/Test.scala
+++ b/test/files/run/t7974/Test.scala
@@ -4,7 +4,7 @@ import scala.tools.partest.BytecodeTest
import scala.tools.nsc.backend.jvm.AsmUtils
import scala.tools.asm.util._
import scala.tools.nsc.util.stringFromWriter
-import scala.collection.convert.decorateAsScala._
+import scala.collection.JavaConverters._
object Test extends BytecodeTest {
def show {
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/t9516.scala b/test/files/run/t9516.scala
new file mode 100644
index 0000000000..b3068dd1ff
--- /dev/null
+++ b/test/files/run/t9516.scala
@@ -0,0 +1,52 @@
+object Test {
+ def main(args: Array[String]): Unit = {
+ intShiftLeftLongConstantFolded()
+ intShiftLeftLongAtRuntime()
+ intShiftLogicalRightLongConstantFolded()
+ intShiftLogicalRightLongAtRuntime()
+ intShiftArithmeticRightLongConstantFolded()
+ intShiftArithmeticRightLongAtRuntime()
+ }
+
+ def intShiftLeftLongConstantFolded(): Unit = {
+ assert(0x01030507 << 36L == 271601776)
+ val r = 0x01030507 << 36L
+ assert(r == 271601776)
+ }
+
+ def intShiftLeftLongAtRuntime(): Unit = {
+ var x: Int = 0x01030507
+ var y: Long = 36L
+ assert(x << y == 271601776)
+ val r = x << y
+ assert(r == 271601776)
+ }
+
+ def intShiftLogicalRightLongConstantFolded(): Unit = {
+ assert(0x90503010 >>> 36L == 151323393)
+ val r = 0x90503010 >>> 36L
+ assert(r == 151323393)
+ }
+
+ def intShiftLogicalRightLongAtRuntime(): Unit = {
+ var x: Int = 0x90503010
+ var y: Long = 36L
+ assert(x >>> y == 151323393)
+ val r = x >>> y
+ assert(r == 151323393)
+ }
+
+ def intShiftArithmeticRightLongConstantFolded(): Unit = {
+ assert(0x90503010 >> 36L == -117112063)
+ val r = 0x90503010 >> 36L
+ assert(r == -117112063)
+ }
+
+ def intShiftArithmeticRightLongAtRuntime(): Unit = {
+ var x: Int = 0x90503010
+ var y: Long = 36L
+ assert(x >> y == -117112063)
+ val r = x >> y
+ assert(r == -117112063)
+ }
+}
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/files/run/various-flat-classpath-types.scala b/test/files/run/various-flat-classpath-types.scala
index d39019e885..bc54ffb6cc 100644
--- a/test/files/run/various-flat-classpath-types.scala
+++ b/test/files/run/various-flat-classpath-types.scala
@@ -5,7 +5,7 @@
import java.io.{File => JFile, FileInputStream, FileOutputStream}
import java.util.zip.{ZipEntry, ZipOutputStream}
import scala.reflect.io.{Directory, File}
-import scala.tools.nsc.classpath.FlatClassPath.RootPackage
+import scala.tools.nsc.util.ClassPath.RootPackage
import scala.tools.nsc.classpath.PackageNameUtils
import scala.tools.nsc.io.Jar
@@ -80,7 +80,6 @@ object Test {
private val compiler = new scala.tools.nsc.MainClass
private val appRunner = new scala.tools.nsc.MainGenericRunner
- private val classPathImplFlag = "-YclasspathImpl:flat"
private val javaClassPath = sys.props("java.class.path")
// creates a test dir in a temporary dir containing compiled files of this test
@@ -166,13 +165,13 @@ object Test {
val classPath = mkPath(javaClassPath, binDir.path, zipsDir.path + "/Bin.zip", jarsDir.path + "/Bin.jar")
val sourcePath = mkPath(srcDir.path, zipsDir.path + "/Src.zip", jarsDir.path + "/Src.jar")
- compiler.process(Array(classPathImplFlag, "-cp", classPath, "-sourcepath", sourcePath,
+ compiler.process(Array("-cp", classPath, "-sourcepath", sourcePath,
"-d", outDir.path, s"${srcDir.path}/Main.scala"))
}
private def runApp(): Unit = {
val classPath = mkPath(javaClassPath, outDir.path, binDir.path, zipsDir.path + "/Bin.zip", jarsDir.path + "/Bin.jar")
- appRunner.process(Array(classPathImplFlag, "-cp", classPath, "Main"))
+ appRunner.process(Array("-cp", classPath, "Main"))
}
private def createStandardSrcHierarchy(baseFileName: String): Unit =
@@ -200,7 +199,7 @@ object Test {
private def compileSrc(baseFileName: String, destination: JFile = outDir): Unit = {
val srcDirPath = srcDir.path
- compiler.process(Array(classPathImplFlag, "-cp", javaClassPath, "-d", destination.path,
+ compiler.process(Array("-cp", javaClassPath, "-d", destination.path,
s"$srcDirPath/$baseFileName.scala", s"$srcDirPath/nested/Nested$baseFileName.scala"))
}
diff --git a/test/files/scalacheck/MutablePriorityQueue.scala b/test/files/scalacheck/MutablePriorityQueue.scala
new file mode 100644
index 0000000000..687e2e7c62
--- /dev/null
+++ b/test/files/scalacheck/MutablePriorityQueue.scala
@@ -0,0 +1,102 @@
+import scala.collection.mutable.PriorityQueue
+import org.scalacheck._
+import Prop._
+import Arbitrary._
+
+object Test extends Properties("PriorityQueue") {
+ type E = Int // the element type used for most/all of the tests
+
+ def checkInvariant[A](pq: PriorityQueue[A])(implicit ord: Ordering[A]): Boolean = {
+ // The ordering invariant in the heap is that parent >= child.
+ // A child at index i has a parent at index i/2 in the priority
+ // queue's internal array. However, that array is padded with
+ // an extra slot in front so that the first real element is at
+ // index 1. The vector below is not padded, so subtract 1 from
+ // every index.
+ import ord._
+ val vec = pq.toVector // elements in same order as pq's internal array
+ 2 until pq.size forall { i => vec(i/2-1) >= vec(i-1) }
+ }
+
+ property("newBuilder (in companion)") = forAll { list: List[E] =>
+ val builder = PriorityQueue.newBuilder[E]
+ for (x <- list) builder += x
+ val pq = builder.result()
+ checkInvariant(pq) &&
+ pq.dequeueAll == list.sorted.reverse
+ }
+
+ property("to[PriorityQueue]") = forAll { list: List[E] =>
+ val pq = list.to[PriorityQueue]
+ checkInvariant(pq) &&
+ pq.dequeueAll == list.sorted.reverse
+ }
+
+ property("apply (in companion)") = forAll { list: List[E] =>
+ val pq = PriorityQueue.apply(list : _*)
+ checkInvariant(pq) &&
+ pq.dequeueAll == list.sorted.reverse
+ }
+
+ property("size, isEmpty") = forAll { list: List[E] =>
+ val pq = PriorityQueue(list : _*)
+ pq.size == list.size && pq.isEmpty == list.isEmpty
+ }
+
+ property("+=") = forAll { (x: E, list: List[E]) =>
+ val pq = PriorityQueue(list : _*)
+ pq += x
+ checkInvariant(pq) &&
+ pq.dequeueAll == (x :: list).sorted.reverse
+ }
+
+ property("++= on empty") = forAll { list: List[E] =>
+ val pq = PriorityQueue.empty[E]
+ pq ++= list
+ checkInvariant(pq) &&
+ pq.dequeueAll == list.sorted.reverse
+ }
+
+ property("++=") = forAll { (list1: List[E], list2: List[E]) =>
+ val pq = PriorityQueue(list1 : _*)
+ pq ++= list2
+ checkInvariant(pq) &&
+ pq.dequeueAll == (list1 ++ list2).sorted.reverse
+ }
+
+ property("reverse") = forAll { list: List[E] =>
+ val pq = PriorityQueue(list : _*).reverse
+ checkInvariant(pq)(implicitly[Ordering[E]].reverse) &&
+ pq.dequeueAll == list.sorted
+ }
+
+ property("reverse then ++=") = forAll { list: List[E] =>
+ val pq = PriorityQueue.empty[E].reverse ++= list
+ checkInvariant(pq)(implicitly[Ordering[E]].reverse) &&
+ pq.dequeueAll == list.sorted
+ }
+
+ property("reverse then +=") = forAll { (x: E, list: List[E]) =>
+ val pq = PriorityQueue(list : _*).reverse += x
+ checkInvariant(pq)(implicitly[Ordering[E]].reverse) &&
+ pq.dequeueAll == (x +: list).sorted
+ }
+
+ property("clone") = forAll { list: List[E] =>
+ val pq = PriorityQueue(list : _*)
+ val c = pq.clone()
+ (pq ne c) &&
+ checkInvariant(c) &&
+ c.dequeueAll == pq.dequeueAll
+ }
+
+ property("dequeue") = forAll { list: List[E] =>
+ list.nonEmpty ==> {
+ val pq = PriorityQueue(list : _*)
+ val x = pq.dequeue()
+ checkInvariant(pq) &&
+ x == list.max && pq.dequeueAll == list.sorted.reverse.tail
+ }
+ }
+
+}
diff --git a/test/instrumented/library/scala/runtime/BoxesRunTime.java b/test/instrumented/library/scala/runtime/BoxesRunTime.java
index 57799bd9b1..05ce2941a8 100644
--- a/test/instrumented/library/scala/runtime/BoxesRunTime.java
+++ b/test/instrumented/library/scala/runtime/BoxesRunTime.java
@@ -278,10 +278,6 @@ public final class BoxesRunTime
else if (n instanceof java.lang.Float) return hashFromFloat((java.lang.Float)n);
else return n.hashCode();
}
- public static int hashFromObject(Object a) {
- if (a instanceof Number) return hashFromNumber((Number)a);
- else return a.hashCode();
- }
private static int unboxCharOrInt(Object arg1, int code) {
if (code == CHAR)
diff --git a/test/instrumented/library/scala/runtime/ScalaRunTime.scala b/test/instrumented/library/scala/runtime/ScalaRunTime.scala
index 6b45a4e9f3..7480ad6fbf 100644
--- a/test/instrumented/library/scala/runtime/ScalaRunTime.scala
+++ b/test/instrumented/library/scala/runtime/ScalaRunTime.scala
@@ -35,15 +35,6 @@ object ScalaRunTime {
private def isArrayClass(clazz: jClass[_], atLevel: Int): Boolean =
clazz.isArray && (atLevel == 1 || isArrayClass(clazz.getComponentType, atLevel - 1))
- def isValueClass(clazz: jClass[_]) = clazz.isPrimitive()
-
- // includes specialized subclasses and future proofed against hypothetical TupleN (for N > 22)
- def isTuple(x: Any) = x != null && x.getClass.getName.startsWith("scala.Tuple")
- def isAnyVal(x: Any) = x match {
- case _: Byte | _: Short | _: Char | _: Int | _: Long | _: Float | _: Double | _: Boolean | _: Unit => true
- case _ => false
- }
-
/** Return the class object representing an array with element class `clazz`.
*/
def arrayClass(clazz: jClass[_]): jClass[_] = {
@@ -52,15 +43,6 @@ object ScalaRunTime {
else java.lang.reflect.Array.newInstance(clazz, 0).getClass
}
- /** Return the class object representing elements in arrays described by a given schematic.
- */
- def arrayElementClass(schematic: Any): jClass[_] = schematic match {
- case cls: jClass[_] => cls.getComponentType
- case tag: ClassTag[_] => tag.runtimeClass
- case _ =>
- throw new UnsupportedOperationException(s"unsupported schematic $schematic (${schematic.getClass})")
- }
-
/** Return the class object representing an unboxed value type,
* e.g. classOf[int], not classOf[java.lang.Integer]. The compiler
* rewrites expressions like 5.getClass to come here.
@@ -122,15 +104,15 @@ object ScalaRunTime {
}
def array_clone(xs: AnyRef): AnyRef = xs match {
- case x: Array[AnyRef] => ArrayRuntime.cloneArray(x)
- case x: Array[Int] => ArrayRuntime.cloneArray(x)
- case x: Array[Double] => ArrayRuntime.cloneArray(x)
- case x: Array[Long] => ArrayRuntime.cloneArray(x)
- case x: Array[Float] => ArrayRuntime.cloneArray(x)
- case x: Array[Char] => ArrayRuntime.cloneArray(x)
- case x: Array[Byte] => ArrayRuntime.cloneArray(x)
- case x: Array[Short] => ArrayRuntime.cloneArray(x)
- case x: Array[Boolean] => ArrayRuntime.cloneArray(x)
+ case x: Array[AnyRef] => x.clone()
+ case x: Array[Int] => x.clone()
+ case x: Array[Double] => x.clone()
+ case x: Array[Long] => x.clone()
+ case x: Array[Float] => x.clone()
+ case x: Array[Char] => x.clone()
+ case x: Array[Byte] => x.clone()
+ case x: Array[Short] => x.clone()
+ case x: Array[Boolean] => x.clone()
case x: Array[Unit] => x
case null => throw new NullPointerException
}
@@ -169,9 +151,6 @@ object ScalaRunTime {
m
}
- def checkInitialized[T <: AnyRef](x: T): T =
- if (x == null) throw new UninitializedError else x
-
def _toString(x: Product): String =
x.productIterator.mkString(x.productPrefix + "(", ",", ")")
@@ -191,72 +170,12 @@ object ScalaRunTime {
}
}
- /** Fast path equality method for inlining; used when -optimise is set.
- */
- @inline def inlinedEquals(x: Object, y: Object): Boolean =
- if (x eq y) true
- else if (x eq null) false
- else if (x.isInstanceOf[java.lang.Number]) BoxesRunTime.equalsNumObject(x.asInstanceOf[java.lang.Number], y)
- else if (x.isInstanceOf[java.lang.Character]) BoxesRunTime.equalsCharObject(x.asInstanceOf[java.lang.Character], y)
- else x.equals(y)
-
- def _equals(x: Product, y: Any): Boolean = y match {
- case y: Product if x.productArity == y.productArity => x.productIterator sameElements y.productIterator
- case _ => false
- }
-
- // hashcode -----------------------------------------------------------
- //
- // Note that these are the implementations called by ##, so they
- // must not call ## themselves.
-
+ /** Implementation of `##`. */
def hash(x: Any): Int =
if (x == null) 0
else if (x.isInstanceOf[java.lang.Number]) BoxesRunTime.hashFromNumber(x.asInstanceOf[java.lang.Number])
else x.hashCode
- def hash(dv: Double): Int = {
- val iv = dv.toInt
- if (iv == dv) return iv
-
- val lv = dv.toLong
- if (lv == dv) return lv.hashCode
-
- val fv = dv.toFloat
- if (fv == dv) fv.hashCode else dv.hashCode
- }
- def hash(fv: Float): Int = {
- val iv = fv.toInt
- if (iv == fv) return iv
-
- val lv = fv.toLong
- if (lv == fv) return hash(lv)
- else fv.hashCode
- }
- def hash(lv: Long): Int = {
- val low = lv.toInt
- val lowSign = low >>> 31
- val high = (lv >>> 32).toInt
- low ^ (high + lowSign)
- }
- def hash(x: Number): Int = runtime.BoxesRunTime.hashFromNumber(x)
-
- // The remaining overloads are here for completeness, but the compiler
- // inlines these definitions directly so they're not generally used.
- def hash(x: Int): Int = x
- def hash(x: Short): Int = x.toInt
- def hash(x: Byte): Int = x.toInt
- def hash(x: Char): Int = x.toInt
- def hash(x: Boolean): Int = if (x) true.hashCode else false.hashCode
- def hash(x: Unit): Int = 0
-
- /** A helper method for constructing case class equality methods,
- * because existential types get in the way of a clean outcome and
- * it's performing a series of Any/Any equals comparisons anyway.
- * See ticket #2867 for specifics.
- */
- def sameElements(xs1: scala.collection.Seq[Any], xs2: scala.collection.Seq[Any]) = xs1 sameElements xs2
-
/** Given any Scala value, convert it to a String.
*
* The primary motivation for this method is to provide a means for
@@ -278,6 +197,9 @@ object ScalaRunTime {
def isScalaClass(x: AnyRef) = packageOf(x) startsWith "scala."
def isScalaCompilerClass(x: AnyRef) = packageOf(x) startsWith "scala.tools.nsc."
+ // includes specialized subclasses and future proofed against hypothetical TupleN (for N > 22)
+ def isTuple(x: Any) = x != null && x.getClass.getName.startsWith("scala.Tuple")
+
// When doing our own iteration is dangerous
def useOwnToString(x: Any) = x match {
// Node extends NodeSeq extends Seq[Node] and MetaData extends Iterable[MetaData]
@@ -345,18 +267,4 @@ object ScalaRunTime {
nl + s + "\n"
}
- private[scala] def checkZip(what: String, coll1: TraversableOnce[_], coll2: TraversableOnce[_]) {
- if (sys.props contains "scala.debug.zip") {
- val xs = coll1.toIndexedSeq
- val ys = coll2.toIndexedSeq
- if (xs.length != ys.length) {
- Console.err.println(
- "Mismatched zip in " + what + ":\n" +
- " this: " + xs.mkString(", ") + "\n" +
- " that: " + ys.mkString(", ")
- )
- (new Exception).getStackTrace.drop(2).take(10).foreach(println)
- }
- }
- }
}
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 de5481d9e2..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 scala.collection.JavaConversions._
-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/collection/mutable/PriorityQueueTest.scala b/test/junit/scala/collection/mutable/PriorityQueueTest.scala
index a14f1bf4c8..faedcf11f0 100644
--- a/test/junit/scala/collection/mutable/PriorityQueueTest.scala
+++ b/test/junit/scala/collection/mutable/PriorityQueueTest.scala
@@ -14,6 +14,12 @@ class PriorityQueueTest {
priorityQueue.enqueue(elements :_*)
@Test
+ def orderingReverseReverse() {
+ val pq = new mutable.PriorityQueue[Nothing]()((_,_)=>42)
+ assert(pq.ord eq pq.reverse.reverse.ord)
+ }
+
+ @Test
def canSerialize() {
val outputStream = new ByteArrayOutputStream()
new ObjectOutputStream(outputStream).writeObject(priorityQueue)
@@ -27,6 +33,7 @@ class PriorityQueueTest {
val objectInputStream = new ObjectInputStream(new ByteArrayInputStream(bytes))
val deserializedPriorityQueue = objectInputStream.readObject().asInstanceOf[PriorityQueue[Int]]
+ //correct sequencing is also tested here:
assert(deserializedPriorityQueue.dequeueAll == elements.sorted.reverse)
}
}
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 2bc8008222..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,21 +111,14 @@ class RunTest extends ClearAfterClass {
}
@Test
- def annotationInfoNotErased(): Unit = {
+ def classOfUnitConstant(): 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))
+ """abstract class A { def f: Class[_] }
+ |class C extends A { final val f = classOf[Unit] }
+ |val c = new C
+ |(c.f, (c: A).f)
+ """.stripMargin
+ val u = Void.TYPE
+ assertEquals(run[(Class[_], Class[_])](code), (u, u))
}
}
diff --git a/test/junit/scala/reflect/internal/PrintersTest.scala b/test/junit/scala/reflect/internal/PrintersTest.scala
index 9bfe6eecb8..2305e7ea50 100644
--- a/test/junit/scala/reflect/internal/PrintersTest.scala
+++ b/test/junit/scala/reflect/internal/PrintersTest.scala
@@ -8,14 +8,6 @@ import scala.reflect.runtime.{currentMirror=>cm}
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-@RunWith(classOf[JUnit4])
-class PrintersTest extends BasePrintTests
- with ClassPrintTests
- with TraitPrintTests
- with ValAndDefPrintTests
- with QuasiTreesPrintTests
- with PackagePrintTests
-
object PrinterHelper {
val toolbox = cm.mkToolBox()
@@ -73,7 +65,8 @@ object PrinterHelper {
import PrinterHelper._
-trait BasePrintTests {
+@RunWith(classOf[JUnit4])
+class BasePrintTest {
@Test def testIdent = assertTreeCode(Ident("*"))("*")
@Test def testConstant1 = assertTreeCode(Literal(Constant("*")))("\"*\"")
@@ -348,7 +341,8 @@ trait BasePrintTests {
@Test def testImport4 = assertPrintedCode("import scala.collection._")
}
-trait ClassPrintTests {
+@RunWith(classOf[JUnit4])
+class ClassPrintTest {
@Test def testClass = assertPrintedCode("class *")
@Test def testClassWithBody = assertPrintedCode(sm"""
@@ -833,7 +827,8 @@ trait ClassPrintTests {
|}""")
}
-trait TraitPrintTests {
+@RunWith(classOf[JUnit4])
+class TraitPrintTest {
@Test def testTrait = assertPrintedCode("trait *")
@Test def testTraitWithBody = assertPrintedCode(sm"""
@@ -953,7 +948,8 @@ trait TraitPrintTests {
|}""")
}
-trait ValAndDefPrintTests {
+@RunWith(classOf[JUnit4])
+class ValAndDefPrintTest {
@Test def testVal1 = assertPrintedCode("val a: scala.Unit = ()")
@Test def testVal2 = assertPrintedCode("val * : scala.Unit = ()")
@@ -1093,7 +1089,8 @@ trait ValAndDefPrintTests {
|}""", wrapCode = true)
}
-trait PackagePrintTests {
+@RunWith(classOf[JUnit4])
+class PackagePrintTest {
@Test def testPackage1 = assertPrintedCode(sm"""
|package foo.bar {
|
@@ -1131,7 +1128,8 @@ trait PackagePrintTests {
|}""", checkTypedTree = false)
}
-trait QuasiTreesPrintTests {
+@RunWith(classOf[JUnit4])
+class QuasiTreesPrintTest {
@Test def testQuasiIdent = assertTreeCode(q"*")("*")
@Test def testQuasiVal = assertTreeCode(q"val * : Unit = null")("val * : Unit = null")
diff --git a/test/junit/scala/runtime/ScalaRunTimeTest.scala b/test/junit/scala/runtime/ScalaRunTimeTest.scala
index 728d8c0ce9..5bfb12610e 100644
--- a/test/junit/scala/runtime/ScalaRunTimeTest.scala
+++ b/test/junit/scala/runtime/ScalaRunTimeTest.scala
@@ -5,70 +5,10 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-/** Tests for the private class DefaultPromise */
+/** Tests for the runtime object ScalaRunTime */
@RunWith(classOf[JUnit4])
class ScalaRunTimeTest {
@Test
- def testIsTuple() {
- import ScalaRunTime.isTuple
- def check(v: Any) = {
- assertTrue(v.toString, isTuple(v))
- }
-
- val s = ""
- check(Tuple1(s))
- check((s, s))
- check((s, s, s))
- check((s, s, s, s))
- check((s, s, s, s, s))
- check((s, s, s, s, s, s))
- check((s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s))
-
- // some specialized variants will have mangled classnames
- check(Tuple1(0))
- check((0, 0))
- check((0, 0, 0))
- check((0, 0, 0, 0))
- check((0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
-
- case class C()
- val c = new C()
- assertFalse(c.toString, isTuple(c))
- }
-
- @Test
def testStingOf() {
import ScalaRunTime.stringOf
import scala.collection._
@@ -109,14 +49,17 @@ class ScalaRunTimeTest {
val tuple1 = Tuple1(0)
assertEquals("(0,)", stringOf(tuple1))
assertEquals("(0,)", stringOf(tuple1, 0))
+ assertEquals("(Array(0),)", stringOf(Tuple1(Array(0))))
val tuple2 = Tuple2(0, 1)
assertEquals("(0,1)", stringOf(tuple2))
assertEquals("(0,1)", stringOf(tuple2, 0))
+ assertEquals("(Array(0),1)", stringOf((Array(0), 1)))
val tuple3 = Tuple3(0, 1, 2)
assertEquals("(0,1,2)", stringOf(tuple3))
assertEquals("(0,1,2)", stringOf(tuple3, 0))
+ assertEquals("(Array(0),1,2)", stringOf((Array(0), 1, 2)))
val x = new Object {
override def toString(): String = "this is the stringOf string"
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/issues/BytecodeTest.scala b/test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala
index 18f8b44391..b2ee8b3a45 100644
--- a/test/junit/scala/issues/BytecodeTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala
@@ -1,88 +1,18 @@
-package scala.issues
+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.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.partest.ASMConverters._
-import scala.tools.testing.ClearAfterClass
-
-object BytecodeTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler()
- def clear(): Unit = { compiler = null }
-}
+import scala.tools.testing.BytecodeTesting
+import scala.tools.testing.BytecodeTesting._
@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")
- }
+class BytecodeTest extends BytecodeTesting {
+ import compiler._
@Test
def t6288bJumpPosition(): Unit = {
@@ -100,9 +30,9 @@ class BytecodeTest extends ClearAfterClass {
| }
|}
""".stripMargin
- val List(mirror, module) = compileClasses(compiler)(code)
+ val List(mirror, module) = compileClasses(code)
- val unapplyLineNumbers = getSingleMethod(module, "unapply").instructions.filter(_.isInstanceOf[LineNumber])
+ val unapplyLineNumbers = getInstructions(module, "unapply").filter(_.isInstanceOf[LineNumber])
assert(unapplyLineNumbers == List(LineNumber(2, Label(0))), unapplyLineNumbers)
val expected = List(
@@ -125,7 +55,7 @@ class BytecodeTest extends ClearAfterClass {
Invoke(INVOKEVIRTUAL, "scala/Predef$", "println", "(Ljava/lang/Object;)V", false)
)
- val mainIns = getSingleMethod(module, "main").instructions filter {
+ val mainIns = getInstructions(module, "main") filter {
case _: LineNumber | _: Invoke | _: Jump => true
case _ => false
}
@@ -147,24 +77,24 @@ class BytecodeTest extends ClearAfterClass {
|}
""".stripMargin
- val List(c) = compileClasses(compiler)(code)
+ val c = compileClass(code)
// t1: no unnecessary GOTOs
- assertSameCode(getSingleMethod(c, "t1"), List(
+ 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(getSingleMethod(c, "t2"), List(
+ 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(getSingleMethod(c, "t3"), List(
+ assertSameCode(getMethod(c, "t3"), List(
// Array ==
VarOp(ALOAD, 1), VarOp(ALOAD, 2), Jump(IF_ACMPEQ, Label(23)),
// AnyRef ==
@@ -183,13 +113,13 @@ class BytecodeTest extends ClearAfterClass {
Label(13), Op(IRETURN))
// t4: one side is known null, so just a null check on the other
- assertSameCode(getSingleMethod(c, "t4"), t4t5)
+ assertSameCode(getMethod(c, "t4"), t4t5)
// t5: one side known null, so just a null check on the other
- assertSameCode(getSingleMethod(c, "t5"), t4t5)
+ assertSameCode(getMethod(c, "t5"), t4t5)
// t6: no unnecessary GOTOs
- assertSameCode(getSingleMethod(c, "t6"), List(
+ 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)),
@@ -198,14 +128,44 @@ class BytecodeTest extends ClearAfterClass {
Label(19), Op(IRETURN)))
// t7: universal equality
- assertInvoke(getSingleMethod(c, "t7"), "scala/runtime/BoxesRunTime", "equals")
+ assertInvoke(getMethod(c, "t7"), "scala/runtime/BoxesRunTime", "equals")
// t8: no null checks invoking equals on modules and constants
- assertSameCode(getSingleMethod(c, "t8"), List(
+ 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 78dbab82f4..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.convert.decorateAsScala._
-
-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,32 +50,32 @@ 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.
val res =
- """ L0: 0: NotNull
- | LINENUMBER 1 L0: 0: NotNull
- | ALOAD 0: 0: NotNull
- |INVOKEVIRTUAL java/lang/Object.toString ()Ljava/lang/String;: 0: NotNull, 1: NotNull
- | ARETURN: 0: NotNull, 1: Unknown1
- | L0: null""".stripMargin
+ """ L0: 0: NotNull
+ | LINENUMBER 1 L0: 0: NotNull
+ | ALOAD 0: 0: NotNull
+ |INVOKEVIRTUAL C.toString ()Ljava/lang/String;: 0: NotNull, 1: NotNull
+ | ARETURN: 0: NotNull, 1: Unknown1
+ | L0: null""".stripMargin
// println(showAllNullnessFrames(newNullnessAnalyzer(m), m))
assertEquals(showAllNullnessFrames(newNullnessAnalyzer(m), m), res)
}
@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 11014f5e64..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.convert.decorateAsScala._
-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 1ce913006d..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.convert.decorateAsScala._
+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()
@@ -67,19 +59,7 @@ class BTypesFromClassfileTest {
// there's a separate InlineInfoTest.
val chk1 = sameBTypes(fromSym.superClass, fromClassfile.superClass, checked)
-
- // was:
- // val chk2 = sameBTypes(fromSym.interfaces, fromClassfile.interfaces, chk1)
-
- // TODO: The new trait encoding emits redundant parents in the backend to avoid linkage errors in invokespecial
- // Need to give this some more thought, maybe do it earlier so it is reflected in the Symbol's info, too.
- val fromSymInterfaces = fromSym.interfaces
- val fromClassFileInterfaces = fromClassfile.interfaces
- val (matching, other) = fromClassFileInterfaces.partition(x => fromSymInterfaces.exists(_.internalName == x.internalName))
- val chk2 = sameBTypes(fromSym.interfaces, matching, chk1)
- for (redundant <- other) {
- assert(matching.exists(x => x.isSubtypeOf(redundant).orThrow), redundant)
- }
+ val chk2 = sameBTypes(fromSym.interfaces, fromClassfile.interfaces, chk1)
// The fromSym info has only member classes, no local or anonymous. The symbol is read from the
// Scala pickle data and only member classes are created / entered.
@@ -103,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 b37b5efa7e..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.convert.decorateAsScala._
-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 a0b9d6b4ed..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.convert.decorateAsScala._
-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 261d6beb96..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._
+import scala.collection.generic.Clearable
+import scala.tools.nsc.backend.jvm.BackendReporting._
+import scala.tools.testing.BytecodeTesting
-import scala.collection.convert.decorateAsScala._
+@RunWith(classOf[JUnit4])
+class InlineInfoTest extends BytecodeTesting {
+ import compiler.global
+ import global.genBCode.bTypes
-object InlineInfoTest extends ClearAfterClass.Clearable {
- var compiler = newCompiler(extraArgs = "-Yopt:l:classpath")
- def clear(): Unit = { compiler = null }
+ override def compilerArgs = "-Yopt:l:classpath"
def notPerRun: List[Clearable] = List(
- compiler.genBCode.bTypes.classBTypeFromInternalName,
- compiler.genBCode.bTypes.byteCodeRepository.compilingClasses,
- compiler.genBCode.bTypes.byteCodeRepository.parsedClasses)
- notPerRun foreach compiler.perRunCaches.unrecordCache
-}
-
-@RunWith(classOf[JUnit4])
-class InlineInfoTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = InlineInfoTest
-
- val compiler = InlineInfoTest.compiler
+ 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 90236265e6..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.convert.decorateAsScala._
-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)
}
@@ -103,22 +75,22 @@ class InlineWarningTest extends ClearAfterClass {
val warns = List(
"""failed to determine if bar should be inlined:
|The method bar()I could not be found in the class A or any of its parents.
- |Note that the following parent classes are defined in Java sources (mixed compilation), no bytecode is available: A""".stripMargin,
+ |Note that the parent class A is defined in a Java source (mixed compilation), no bytecode is available.""".stripMargin,
"""B::flop()I is annotated @inline but could not be inlined:
|Failed to check if B::flop()I can be safely inlined to B without causing an IllegalAccessError. Checking instruction INVOKESTATIC A.bar ()I failed:
|The method bar()I could not be found in the class A or any of its parents.
- |Note that the following parent classes are defined in Java sources (mixed compilation), no bytecode is available: A""".stripMargin)
+ |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 884027cd90..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.collection.JavaConverters._
+import scala.tools.asm.Opcodes._
import scala.tools.asm.tree._
-import scala.tools.testing.AssertUtil._
-
-import CodeGenTools._
-import scala.tools.partest.ASMConverters
-import ASMConverters._
-import AsmUtils._
-
-import scala.collection.convert.decorateAsScala._
-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.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 6562f81e4c..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.convert.decorateAsScala._
-
-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 9079ca248a..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.convert.decorateAsScala._
-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 }
-}
-
-@RunWith(classOf[JUnit4])
-class InlinerTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = InlinerTest
+ bTypes.classBTypeFromInternalName,
+ bTypes.byteCodeRepository.compilingClasses,
+ bTypes.byteCodeRepository.parsedClasses,
+ bTypes.callGraph.callsites)
+ notPerRun foreach global.perRunCaches.unrecordCache
- 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
@@ -428,12 +416,12 @@ class InlinerTest extends ClearAfterClass {
"""B::flop()I is annotated @inline but could not be inlined:
|Failed to check if B::flop()I can be safely inlined to B without causing an IllegalAccessError. Checking instruction INVOKESTATIC A.bar ()I failed:
|The method bar()I could not be found in the class A or any of its parents.
- |Note that the following parent classes are defined in Java sources (mixed compilation), no bytecode is available: A""".stripMargin
+ |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; 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,21 +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"))
- }
-
- @Test
- def inlineMixinMethods(): Unit = {
- val code =
- """trait T {
- | @inline final def f = 1
- |}
- |class C extends T
- """.stripMargin
- val List(c, t) = compile(code)
- // the static implementation method is inlined into the mixin, so there's no invocation in the mixin
- assertNoInvoke(getSingleMethod(c, "f"))
+ assertNoInvoke(getMethod(c, "t1"))
+ assertNoInvoke(getMethod(c, "t2"))
}
@Test
@@ -485,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
@@ -506,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
@@ -521,7 +496,7 @@ class InlinerTest extends ClearAfterClass {
|}
""".stripMargin
val List(c, t) = compile(code)
- assertNoInvoke(getSingleMethod(c, "t1"))
+ assertNoInvoke(getMethod(c, "t1"))
}
@Test
@@ -545,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(oModule, "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
@@ -571,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
@@ -649,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
@@ -679,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
@@ -694,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
@@ -709,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))
}
@@ -790,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")
@@ -846,11 +821,11 @@ class InlinerTest extends ClearAfterClass {
val warn =
"""failed to determine if <init> should be inlined:
|The method <init>()V could not be found in the class A$Inner or any of its parents.
- |Note that the following parent classes could not be found on the classpath: A$Inner""".stripMargin
+ |Note that the parent class A$Inner could not be found on the classpath.""".stripMargin
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})
@@ -894,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
@@ -912,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
@@ -927,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
@@ -940,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
@@ -967,19 +942,13 @@ class InlinerTest extends ClearAfterClass {
val List(c, _, _) = compile(code)
- val t1 = getSingleMethod(c, "t1")
- assert(t1.instructions forall { // indy is eliminated by push-pop
- case _: InvokeDynamic => false
- case _ => true
- })
+ 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")
- assert(t2.instructions forall { // indy is eliminated by push-pop
- case _: InvokeDynamic => false
- case _ => true
- })
+ val t2 = getMethod(c, "t2")
+ assertNoIndy(t2)
assertInvoke(t2, "M$", "M$$$anonfun$1")
}
@@ -995,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")
@@ -1024,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")
@@ -1064,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
@@ -1097,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
@@ -1128,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
@@ -1152,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
@@ -1176,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
@@ -1195,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
@@ -1304,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
@@ -1360,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"))
}
@@ -1401,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
@@ -1431,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)
@@ -1459,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*/,
@@ -1479,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))
@@ -1491,16 +1460,70 @@ 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
def sd86(): Unit = {
val code =
- """trait T { @inline def f = 1 } // note that f is not final
- |class C extends T
+ """trait T1 { @inline def f = 999 }
+ |trait T2 { self: T1 => @inline override def f = 1 } // note that f is not final
+ |class C extends T1 with T2
+ """.stripMargin
+ val List(c, t1, t2) = compile(code, allowMessage = _ => true)
+ // the forwarder C.f is inlined, so there's no invocation
+ assertSameSummary(getMethod(c, "f"), List(ICONST_1, IRETURN))
+ }
+
+ @Test
+ def sd140(): Unit = {
+ val code =
+ """trait T { @inline def f = 0 }
+ |trait U extends T { @inline override def f = 1 }
+ |trait V extends T { def m = 0 }
+ |final class K extends V with U { override def m = super[V].m }
+ |class C { def t = (new K).f }
""".stripMargin
- val List(c, t) = compile(code, allowMessage = _ => true)
- assertSameSummary(getSingleMethod(c, "f"), List(ICONST_1, IRETURN))
+ val c :: _ = compile(code)
+ assertSameSummary(getMethod(c, "t"), List(NEW, "<init>", ICONST_1, IRETURN)) // ICONST_1, U.f is inlined (not T.f)
+ }
+
+ // 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 {
+ | def consume(x: Int) = ()
+ | def t(a: Array[Int]): Unit = a foreach consume
+ |}
+ """.stripMargin
+ val List(c) = compile(code)
+ 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 0a9a26cda7..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.convert.decorateAsScala._
-
-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 4db2657c1b..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,30 +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.collection.JavaConverters._
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.convert.decorateAsScala._
-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.nsc.backend.jvm.BTypes.{InlineInfo, MethodInlineInfo}
+import scala.tools.testing.BytecodeTesting
@RunWith(classOf[JUnit4])
-class ScalaInlineInfoTest extends ClearAfterClass {
- ClearAfterClass.stateToClear = ScalaInlineInfoTest
-
- val compiler = newCompiler()
+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
@@ -79,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
@@ -113,10 +103,7 @@ class ScalaInlineInfoTest extends ClearAfterClass {
val infoC = inlineInfo(c)
val expectC = InlineInfo(false, None, Map(
"O()LT$O$;" -> MethodInlineInfo(true ,false,false),
- "f1()I" -> MethodInlineInfo(false,false,false),
- "f3()I" -> MethodInlineInfo(false,false,false),
- "f4()Ljava/lang/String;" -> MethodInlineInfo(false,true ,false),
- "f5()I" -> MethodInlineInfo(true ,false,false),
+ "O$lzycompute()LT$O$;" -> MethodInlineInfo(true, false,false),
"f6()I" -> MethodInlineInfo(false,false,false),
"x1()I" -> MethodInlineInfo(false,false,false),
"T$_setter_$x1_$eq(I)V" -> MethodInlineInfo(false,false,false),
@@ -159,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,4 +158,16 @@ class ScalaInlineInfoTest extends ClearAfterClass {
("U",None)))
}
+
+ @Test
+ def lzyComputeInlineInfo(): Unit = {
+ val code = "class C { object O }"
+ val List(c, om) = compileClasses(code)
+ val infoC = inlineInfo(c)
+ val expected = Map(
+ "<init>()V" -> MethodInlineInfo(false,false,false),
+ "O$lzycompute()LC$O$;" -> MethodInlineInfo(true,false,false),
+ "O()LC$O$;" -> MethodInlineInfo(true,false,false))
+ assert(infoC.methodInfos == expected, mapDiff(infoC.methodInfos, expected))
+ }
}
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/classpath/AggregateFlatClassPathTest.scala b/test/junit/scala/tools/nsc/classpath/AggregateClassPathTest.scala
index 9a004d5e0e..a7aca31ee3 100644
--- a/test/junit/scala/tools/nsc/classpath/AggregateFlatClassPathTest.scala
+++ b/test/junit/scala/tools/nsc/classpath/AggregateClassPathTest.scala
@@ -10,6 +10,7 @@ import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import scala.reflect.io.VirtualFile
import scala.tools.nsc.io.AbstractFile
+import scala.tools.nsc.util.ClassPath
/**
* Tests whether AggregateFlatClassPath returns correct entries taken from
@@ -17,14 +18,14 @@ import scala.tools.nsc.io.AbstractFile
* (in the case of the repeated entry for a class or a source it returns the first one).
*/
@RunWith(classOf[JUnit4])
-class AggregateFlatClassPathTest {
+class AggregateClassPathTest {
- private class TestFlatClassPath extends FlatClassPath {
+ private abstract class TestClassPathBase extends ClassPath {
override def packages(inPackage: String): Seq[PackageEntry] = unsupported
override def sources(inPackage: String): Seq[SourceFileEntry] = unsupported
override def classes(inPackage: String): Seq[ClassFileEntry] = unsupported
- override def list(inPackage: String): FlatClassPathEntries = unsupported
+ override def list(inPackage: String): ClassPathEntries = unsupported
override def findClassFile(name: String): Option[AbstractFile] = unsupported
override def asClassPathStrings: Seq[String] = unsupported
@@ -32,7 +33,7 @@ class AggregateFlatClassPathTest {
override def asURLs: Seq[URL] = unsupported
}
- private case class TestClassPath(virtualPath: String, classesInPackage: EntryNamesInPackage*) extends TestFlatClassPath {
+ private case class TestClassPath(virtualPath: String, classesInPackage: EntryNamesInPackage*) extends TestClassPathBase {
override def classes(inPackage: String): Seq[ClassFileEntry] =
for {
@@ -43,10 +44,10 @@ class AggregateFlatClassPathTest {
override def sources(inPackage: String): Seq[SourceFileEntry] = Nil
// we'll ignore packages
- override def list(inPackage: String): FlatClassPathEntries = FlatClassPathEntries(Nil, classes(inPackage))
+ override def list(inPackage: String): ClassPathEntries = ClassPathEntries(Nil, classes(inPackage))
}
- private case class TestSourcePath(virtualPath: String, sourcesInPackage: EntryNamesInPackage*) extends TestFlatClassPath {
+ private case class TestSourcePath(virtualPath: String, sourcesInPackage: EntryNamesInPackage*) extends TestClassPathBase {
override def sources(inPackage: String): Seq[SourceFileEntry] =
for {
@@ -57,7 +58,7 @@ class AggregateFlatClassPathTest {
override def classes(inPackage: String): Seq[ClassFileEntry] = Nil
// we'll ignore packages
- override def list(inPackage: String): FlatClassPathEntries = FlatClassPathEntries(Nil, sources(inPackage))
+ override def list(inPackage: String): ClassPathEntries = ClassPathEntries(Nil, sources(inPackage))
}
private case class EntryNamesInPackage(inPackage: String)(val names: String*)
@@ -88,7 +89,7 @@ class AggregateFlatClassPathTest {
private def virtualFile(pathPrefix: String, inPackage: String, fileName: String, extension: String) = {
val packageDirs =
- if (inPackage == FlatClassPath.RootPackage) ""
+ if (inPackage == ClassPath.RootPackage) ""
else inPackage.split('.').mkString("/", "/", "")
new VirtualFile(fileName + extension, s"$pathPrefix$packageDirs/$fileName$extension")
}
@@ -101,12 +102,12 @@ class AggregateFlatClassPathTest {
TestSourcePath(dir2, EntryNamesInPackage(pkg3)("J", "K", "L"))
)
- AggregateFlatClassPath(partialClassPaths)
+ AggregateClassPath(partialClassPaths)
}
@Test
def testGettingPackages: Unit = {
- case class ClassPathWithPackages(packagesInPackage: EntryNamesInPackage*) extends TestFlatClassPath {
+ case class ClassPathWithPackages(packagesInPackage: EntryNamesInPackage*) extends TestClassPathBase {
override def packages(inPackage: String): Seq[PackageEntry] =
packagesInPackage.find(_.inPackage == inPackage).map(_.names).getOrElse(Nil) map PackageEntryImpl
}
@@ -115,7 +116,7 @@ class AggregateFlatClassPathTest {
ClassPathWithPackages(EntryNamesInPackage(pkg1)("pkg1.c", "pkg1.b", "pkg1.a"),
EntryNamesInPackage(pkg2)("pkg2.d", "pkg2.a", "pkg2.e"))
)
- val cp = AggregateFlatClassPath(partialClassPaths)
+ val cp = AggregateClassPath(partialClassPaths)
val packagesInPkg1 = Seq("pkg1.a", "pkg1.d", "pkg1.f", "pkg1.c", "pkg1.b")
assertEquals(packagesInPkg1, cp.packages(pkg1).map(_.name))
@@ -156,7 +157,7 @@ class AggregateFlatClassPathTest {
TestClassPath(dir4, EntryNamesInPackage(pkg2)("A", "H", "I")),
TestClassPath(dir2, EntryNamesInPackage(pkg3)("J", "K", "L"))
)
- val cp = AggregateFlatClassPath(partialClassPaths)
+ val cp = AggregateClassPath(partialClassPaths)
val sourcesInPkg1 = Seq(sourceFileEntry(dir2, pkg1, "C"),
sourceFileEntry(dir2, pkg1, "B"),
@@ -190,7 +191,7 @@ class AggregateFlatClassPathTest {
)
assertEquals(classesAndSourcesInPkg1, cp.list(pkg1).classesAndSources)
- assertEquals(FlatClassPathEntries(Nil, Nil), cp.list(nonexistingPkg))
+ assertEquals(ClassPathEntries(Nil, Nil), cp.list(nonexistingPkg))
}
@Test
diff --git a/test/junit/scala/tools/nsc/classpath/FlatClassPathResolverTest.scala b/test/junit/scala/tools/nsc/classpath/PathResolverBaseTest.scala
index 5dee488285..d3d4289d8b 100644
--- a/test/junit/scala/tools/nsc/classpath/FlatClassPathResolverTest.scala
+++ b/test/junit/scala/tools/nsc/classpath/PathResolverBaseTest.scala
@@ -9,20 +9,17 @@ import org.junit._
import org.junit.rules.TemporaryFolder
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import scala.annotation.tailrec
-import scala.tools.nsc.io.AbstractFile
import scala.tools.nsc.util.ClassPath
import scala.tools.nsc.Settings
-import scala.tools.util.FlatClassPathResolver
import scala.tools.util.PathResolver
@RunWith(classOf[JUnit4])
-class FlatClassPathResolverTest {
+class PathResolverBaseTest {
val tempDir = new TemporaryFolder()
- private val packagesToTest = List(FlatClassPath.RootPackage, "scala", "scala.reflect", "scala.reflect.io")
- private val classFilesToFind = List("scala.tools.util.FlatClassPathResolver",
+ private val packagesToTest = List(ClassPath.RootPackage, "scala", "scala.reflect", "scala.reflect.io")
+ private val classFilesToFind = List("scala.tools.util.PathResolver",
"scala.reflect.io.AbstractFile",
"scala.collection.immutable.List",
"scala.Option",
@@ -60,7 +57,7 @@ class FlatClassPathResolverTest {
def deleteTempDir: Unit = tempDir.delete()
private def createFlatClassPath(settings: Settings) =
- new FlatClassPathResolver(settings).result
+ new PathResolver(settings).result
@Test
def testEntriesFromListOperationAgainstSeparateMethods: Unit = {
@@ -70,7 +67,7 @@ class FlatClassPathResolverTest {
val packages = classPath.packages(inPackage)
val classes = classPath.classes(inPackage)
val sources = classPath.sources(inPackage)
- val FlatClassPathEntries(packagesFromList, classesAndSourcesFromList) = classPath.list(inPackage)
+ val ClassPathEntries(packagesFromList, classesAndSourcesFromList) = classPath.list(inPackage)
val packageNames = packages.map(_.name).sorted
val packageNamesFromList = packagesFromList.map(_.name).sorted
@@ -96,52 +93,6 @@ class FlatClassPathResolverTest {
}
@Test
- def testCreatedEntriesAgainstRecursiveClassPath: Unit = {
- val flatClassPath = createFlatClassPath(settings)
- val recursiveClassPath = new PathResolver(settings).result
-
- def compareEntriesInPackage(inPackage: String): Unit = {
-
- @tailrec
- def traverseToPackage(packageNameParts: Seq[String], cp: ClassPath[AbstractFile]): ClassPath[AbstractFile] = {
- packageNameParts match {
- case Nil => cp
- case h :: t =>
- cp.packages.find(_.name == h) match {
- case Some(nestedCp) => traverseToPackage(t, nestedCp)
- case _ => throw new Exception(s"There's no package $inPackage in recursive classpath - error when searching for '$h'")
- }
- }
- }
-
- val packageNameParts = if (inPackage == FlatClassPath.RootPackage) Nil else inPackage.split('.').toList
- val recursiveClassPathInPackage = traverseToPackage(packageNameParts, recursiveClassPath)
-
- val flatCpPackages = flatClassPath.packages(inPackage).map(_.name)
- val pkgPrefix = PackageNameUtils.packagePrefix(inPackage)
- val recursiveCpPackages = recursiveClassPathInPackage.packages.map(pkgPrefix + _.name)
- assertEquals(s"Packages in package '$inPackage' on flat cp should be the same as on the recursive cp",
- recursiveCpPackages, flatCpPackages)
-
- val flatCpSources = flatClassPath.sources(inPackage).map(_.name).sorted
- val recursiveCpSources = recursiveClassPathInPackage.classes
- .filter(_.source.nonEmpty)
- .map(_.name).sorted
- assertEquals(s"Source entries in package '$inPackage' on flat cp should be the same as on the recursive cp",
- recursiveCpSources, flatCpSources)
-
- val flatCpClasses = flatClassPath.classes(inPackage).map(_.name).sorted
- val recursiveCpClasses = recursiveClassPathInPackage.classes
- .filter(_.binary.nonEmpty)
- .map(_.name).sorted
- assertEquals(s"Class entries in package '$inPackage' on flat cp should be the same as on the recursive cp",
- recursiveCpClasses, flatCpClasses)
- }
-
- packagesToTest foreach compareEntriesInPackage
- }
-
- @Test
def testFindClassFile: Unit = {
val classPath = createFlatClassPath(settings)
classFilesToFind foreach { className =>
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/symtab/SymbolTableForUnitTesting.scala b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala
index 812c298c48..8cc7aefdd3 100644
--- a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala
+++ b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala
@@ -3,11 +3,8 @@ package symtab
import scala.reflect.ClassTag
import scala.reflect.internal.{NoPhase, Phase, SomePhase}
-import scala.tools.nsc.classpath.FlatClassPath
-import scala.tools.nsc.settings.ClassPathRepresentationType
-import scala.tools.util.FlatClassPathResolver
import scala.tools.util.PathResolver
-import util.{ClassFileLookup, ClassPath}
+import util.ClassPath
import io.AbstractFile
/**
@@ -30,8 +27,7 @@ class SymbolTableForUnitTesting extends SymbolTable {
override def isCompilerUniverse: Boolean = true
- def classPath = platform.classPath
- def flatClassPath: FlatClassPath = platform.flatClassPath
+ def classPath: ClassPath = platform.classPath
object platform extends backend.Platform {
val symbolTable: SymbolTableForUnitTesting.this.type = SymbolTableForUnitTesting.this
@@ -39,22 +35,12 @@ class SymbolTableForUnitTesting extends SymbolTable {
def platformPhases: List[SubComponent] = Nil
- lazy val classPath: ClassPath[AbstractFile] = {
- assert(settings.YclasspathImpl.value == ClassPathRepresentationType.Recursive,
- "It's not possible to use the recursive classpath representation, when it's not the chosen classpath scanning method")
- new PathResolver(settings).result
- }
-
- private[nsc] lazy val flatClassPath: FlatClassPath = {
- assert(settings.YclasspathImpl.value == ClassPathRepresentationType.Flat,
- "It's not possible to use the flat classpath representation, when it's not the chosen classpath scanning method")
- new FlatClassPathResolver(settings).result
- }
+ private[nsc] lazy val classPath: ClassPath = new PathResolver(settings).result
def isMaybeBoxed(sym: Symbol): Boolean = ???
def needCompile(bin: AbstractFile, src: AbstractFile): Boolean = ???
def externalEquals: Symbol = ???
- def updateClassPath(subst: Map[ClassFileLookup[AbstractFile], ClassFileLookup[AbstractFile]]): Unit = ???
+ def updateClassPath(subst: Map[ClassPath, ClassPath]): Unit = ???
}
object loaders extends symtab.SymbolLoaders {
@@ -69,10 +55,7 @@ class SymbolTableForUnitTesting extends SymbolTable {
class GlobalMirror extends Roots(NoSymbol) {
val universe: SymbolTableForUnitTesting.this.type = SymbolTableForUnitTesting.this
- def rootLoader: LazyType = settings.YclasspathImpl.value match {
- case ClassPathRepresentationType.Flat => new loaders.PackageLoaderUsingFlatClassPath(FlatClassPath.RootPackage, flatClassPath)
- case ClassPathRepresentationType.Recursive => new loaders.PackageLoader(classPath)
- }
+ def rootLoader: LazyType = new loaders.PackageLoader(ClassPath.RootPackage, classPath)
override def toString = "compiler mirror"
}
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/util/ClassPathImplComparator.scala b/test/junit/scala/tools/nsc/util/ClassPathImplComparator.scala
deleted file mode 100644
index f2926e3e17..0000000000
--- a/test/junit/scala/tools/nsc/util/ClassPathImplComparator.scala
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (c) 2014 Contributor. All rights reserved.
- */
-package scala.tools.nsc.util
-
-import scala.reflect.io.AbstractFile
-import scala.tools.nsc.Settings
-import scala.tools.nsc.settings.ClassPathRepresentationType
-import scala.tools.util.PathResolverFactory
-
-/**
- * Simple application to compare efficiency of the recursive and the flat classpath representations
- */
-object ClassPathImplComparator {
-
- private class TestSettings extends Settings {
- val checkClasses = PathSetting("-checkClasses", "Specify names of classes which should be found separated with ;", "")
- val requiredIterations = IntSetting("-requiredIterations",
- "Repeat tests specified number of times (to check e.g. impact of caches)", 1, Some((1, Int.MaxValue)), (_: String) => None)
- val cpCreationRepetitions = IntSetting("-cpCreationRepetitions",
- "Repeat tests specified number of times (to check e.g. impact of caches)", 1, Some((1, Int.MaxValue)), (_: String) => None)
- val cpLookupRepetitions = IntSetting("-cpLookupRepetitions",
- "Repeat tests specified number of times (to check e.g. impact of caches)", 1, Some((1, Int.MaxValue)), (_: String) => None)
- }
-
- private class DurationStats(name: String) {
- private var sum = 0L
- private var iterations = 0
-
- def noteMeasuredTime(millis: Long): Unit = {
- sum += millis
- iterations += 1
- }
-
- def printResults(): Unit = {
- val avg = if (iterations == 0) 0 else sum.toDouble / iterations
- println(s"$name - total duration: $sum ms; iterations: $iterations; avg: $avg ms")
- }
- }
-
- private lazy val defaultClassesToFind = List(
- "scala.collection.immutable.List",
- "scala.Option",
- "scala.Int",
- "scala.collection.immutable.Vector",
- "scala.util.hashing.MurmurHash3"
- )
-
- private val oldCpCreationStats = new DurationStats("Old classpath - create")
- private val oldCpSearchingStats = new DurationStats("Old classpath - search")
-
- private val flatCpCreationStats = new DurationStats("Flat classpath - create")
- private val flatCpSearchingStats = new DurationStats("Flat classpath - search")
-
- def main(args: Array[String]): Unit = {
-
- if (args contains "-help")
- usage()
- else {
- val oldCpSettings = loadSettings(args.toList, ClassPathRepresentationType.Recursive)
- val flatCpSettings = loadSettings(args.toList, ClassPathRepresentationType.Flat)
-
- val classesToCheck = oldCpSettings.checkClasses.value
- val classesToFind =
- if (classesToCheck.isEmpty) defaultClassesToFind
- else classesToCheck.split(";").toList
-
- def doTest(classPath: => ClassFileLookup[AbstractFile], cpCreationStats: DurationStats, cpSearchingStats: DurationStats,
- cpCreationRepetitions: Int, cpLookupRepetitions: Int)= {
-
- def createClassPaths() = (1 to cpCreationRepetitions).map(_ => classPath).last
- def testClassLookup(cp: ClassFileLookup[AbstractFile]): Boolean = (1 to cpCreationRepetitions).foldLeft(true) {
- case (a, _) => a && checkExistenceOfClasses(classesToFind)(cp)
- }
-
- val cp = withMeasuredTime("Creating classpath", createClassPaths(), cpCreationStats)
- val result = withMeasuredTime("Searching for specified classes", testClassLookup(cp), cpSearchingStats)
- println(s"The end of the test case. All expected classes found = $result \n")
- }
-
- (1 to oldCpSettings.requiredIterations.value) foreach { iteration =>
- if (oldCpSettings.requiredIterations.value > 1)
- println(s"Iteration no $iteration")
-
- println("Recursive (old) classpath representation:")
- doTest(PathResolverFactory.create(oldCpSettings).result, oldCpCreationStats, oldCpSearchingStats,
- oldCpSettings.cpCreationRepetitions.value, oldCpSettings.cpLookupRepetitions.value)
-
- println("Flat classpath representation:")
- doTest(PathResolverFactory.create(flatCpSettings).result, flatCpCreationStats, flatCpSearchingStats,
- flatCpSettings.cpCreationRepetitions.value, flatCpSettings.cpLookupRepetitions.value)
- }
-
- if (oldCpSettings.requiredIterations.value > 1) {
- println("\nOld classpath - summary")
- oldCpCreationStats.printResults()
- oldCpSearchingStats.printResults()
-
- println("\nFlat classpath - summary")
- flatCpCreationStats.printResults()
- flatCpSearchingStats.printResults()
- }
- }
- }
-
- /**
- * Prints usage information
- */
- private def usage(): Unit =
- println("""Use classpath and sourcepath options like in the case of e.g. 'scala' command.
- | There are also two additional options:
- | -checkClasses <semicolon separated class names> Specify names of classes which should be found
- | -requiredIterations <int value> Repeat tests specified count of times (to check e.g. impact of caches)
- | Note: Option -YclasspathImpl will be set automatically for each case.
- """.stripMargin.trim)
-
- private def loadSettings(args: List[String], implType: String) = {
- val settings = new TestSettings()
- settings.processArguments(args, processAll = true)
- settings.YclasspathImpl.value = implType
- if (settings.classpath.isDefault)
- settings.classpath.value = sys.props("java.class.path")
- settings
- }
-
- private def withMeasuredTime[T](operationName: String, f: => T, durationStats: DurationStats): T = {
- val startTime = System.currentTimeMillis()
- val res = f
- val elapsed = System.currentTimeMillis() - startTime
- durationStats.noteMeasuredTime(elapsed)
- println(s"$operationName - elapsed $elapsed ms")
- res
- }
-
- private def checkExistenceOfClasses(classesToCheck: Seq[String])(classPath: ClassFileLookup[AbstractFile]): Boolean =
- classesToCheck.foldLeft(true) {
- case (res, classToCheck) =>
- val found = classPath.findClass(classToCheck).isDefined
- if (!found)
- println(s"Class $classToCheck not found") // of course in this case the measured time will be affected by IO operation
- found
- }
-}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala b/test/junit/scala/tools/testing/BytecodeTesting.scala
index fe43ed2f6a..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 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 compileClassesSeparately(codes: List[String], extraArgs: String = "", allowMessage: StoreReporter#Info => Boolean = _ => false, afterEach: AbstractFile => Unit = _ => ()): List[ClassNode] = {
+ readAsmClasses(compileToBytesSeparately(codes, extraArgs, allowMessage, afterEach))
}
- 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 = {
@@ -206,23 +227,57 @@ object CodeGenTools {
assert(actual == expected, s"\nFound : ${quote(actual)}\nExpected: ${quote(expected)}")
}
- def getSingleMethod(classNode: ClassNode, name: String): Method =
- convertMethod(classNode.methods.asScala.toList.find(_.name == name).get)
+ def assertNoIndy(m: Method): Unit = assertNoIndy(m.instructions)
+ def assertNoIndy(l: List[Instruction]) = {
+ val indy = l collect { case i: InvokeDynamic => i }
+ assert(indy.isEmpty, indy)
+ }
+
+ 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 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 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 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))
+}
diff --git a/test/junit/scala/util/matching/RegexTest.scala b/test/junit/scala/util/matching/RegexTest.scala
index 5b13397d6a..06d0445e1c 100644
--- a/test/junit/scala/util/matching/RegexTest.scala
+++ b/test/junit/scala/util/matching/RegexTest.scala
@@ -6,6 +6,8 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
+import scala.tools.testing.AssertUtil._
+
@RunWith(classOf[JUnit4])
class RegexTest {
@Test def t8022CharSequence(): Unit = {
@@ -44,4 +46,66 @@ class RegexTest {
}
assertEquals(List((1,2),(3,4),(5,6)), z)
}
+
+ @Test def `SI-9666: use inline group names`(): Unit = {
+ val r = new Regex("a(?<Bee>b*)c")
+ val ms = r findAllIn "stuff abbbc more abc and so on"
+ assertTrue(ms.hasNext)
+ assertEquals("abbbc", ms.next())
+ assertEquals("bbb", ms group "Bee")
+ assertTrue(ms.hasNext)
+ assertEquals("abc", ms.next())
+ assertEquals("b", ms group "Bee")
+ assertFalse(ms.hasNext)
+ }
+
+ @Test def `SI-9666: use explicit group names`(): Unit = {
+ val r = new Regex("a(b*)c", "Bee")
+ val ms = r findAllIn "stuff abbbc more abc and so on"
+ assertTrue(ms.hasNext)
+ assertEquals("abbbc", ms.next())
+ assertEquals("bbb", ms group "Bee")
+ assertTrue(ms.hasNext)
+ assertEquals("abc", ms.next())
+ assertEquals("b", ms group "Bee")
+ assertFalse(ms.hasNext)
+ }
+
+ @Test def `SI-9666: fall back to explicit group names`(): Unit = {
+ val r = new Regex("a(?<Bar>b*)c", "Bee")
+ val ms = r findAllIn "stuff abbbc more abc and so on"
+ assertTrue(ms.hasNext)
+ assertEquals("abbbc", ms.next())
+ assertEquals("bbb", ms group "Bee")
+ assertEquals("bbb", ms group "Bar")
+ assertTrue(ms.hasNext)
+ assertEquals("abc", ms.next())
+ assertEquals("b", ms group "Bee")
+ assertEquals("b", ms group "Bar")
+ assertFalse(ms.hasNext)
+ }
+
+ //type NoGroup = NoSuchElementException
+ type NoGroup = IllegalArgumentException
+
+ @Test def `SI-9666: throw on bad name`(): Unit = {
+ assertThrows[NoGroup] {
+ val r = new Regex("a(?<Bar>b*)c")
+ val ms = r findAllIn "stuff abbbc more abc and so on"
+ assertTrue(ms.hasNext)
+ ms group "Bee"
+ }
+ assertThrows[NoGroup] {
+ val r = new Regex("a(?<Bar>b*)c", "Bar")
+ val ms = r findAllIn "stuff abbbc more abc and so on"
+ assertTrue(ms.hasNext)
+ ms group "Bee"
+ }
+ assertThrows[NoGroup] {
+ val r = new Regex("a(b*)c", "Bar")
+ val ms = r findAllIn "stuff abbbc more abc and so on"
+ assertTrue(ms.hasNext)
+ ms group "Bee"
+ }
+ }
}
diff --git a/test/files/run/origins.check b/test/pending/run/origins.check
index b12cb6e38f..b12cb6e38f 100644
--- a/test/files/run/origins.check
+++ b/test/pending/run/origins.check
diff --git a/test/files/run/origins.flags b/test/pending/run/origins.flags
index 690753d807..690753d807 100644
--- a/test/files/run/origins.flags
+++ b/test/pending/run/origins.flags
diff --git a/test/files/run/origins.scala b/test/pending/run/origins.scala
index 6529351d3c..6529351d3c 100644
--- a/test/files/run/origins.scala
+++ b/test/pending/run/origins.scala
diff --git a/test/scaladoc/run/t9752.check b/test/scaladoc/run/t9752.check
new file mode 100644
index 0000000000..daeafb8ecc
--- /dev/null
+++ b/test/scaladoc/run/t9752.check
@@ -0,0 +1,5 @@
+List(Body(List(Paragraph(Chain(List(Summary(Text())))), Code(class A
+
+
+class B))))
+Done.
diff --git a/test/scaladoc/run/t9752.scala b/test/scaladoc/run/t9752.scala
new file mode 100644
index 0000000000..b11c7f5c32
--- /dev/null
+++ b/test/scaladoc/run/t9752.scala
@@ -0,0 +1,28 @@
+import scala.tools.nsc.doc.model._
+import scala.tools.partest.ScaladocModelTest
+
+object Test extends ScaladocModelTest {
+
+ override def code = s"""
+ /**
+ * Foo
+ *
+ * @example
+ * {{{
+ * class A
+ *
+ *
+ * class B
+ * }}}
+ */
+ object Foo
+ """
+
+ def scaladocSettings = ""
+
+ def testModel(root: Package) = {
+ import access._
+ val obj = root._object("Foo")
+ println(obj.comment.get.example)
+ }
+}
diff --git a/versions.properties b/versions.properties
index d4112325d2..0d80d5b1cf 100644
--- a/versions.properties
+++ b/versions.properties
@@ -26,11 +26,11 @@ scala-xml.version.number=1.0.5
scala-parser-combinators.version.number=1.0.4
scala-swing.version.number=2.0.0-M2
scala-swing.version.osgi=2.0.0.M2
-jline.version=2.12.1
+jline.version=2.14.1
scala-asm.version=5.0.4-scala-3
# external modules, used internally (not shipped)
-partest.version.number=1.0.13
+partest.version.number=1.0.14
scalacheck.version.number=1.11.6
# TODO: modularize the compiler