diff options
210 files changed, 3830 insertions, 2277 deletions
diff --git a/bincompat-backward.whitelist.conf b/bincompat-backward.whitelist.conf index d4db9962e7..9ea78a2977 100644 --- a/bincompat-backward.whitelist.conf +++ b/bincompat-backward.whitelist.conf @@ -32,6 +32,241 @@ filter { { matchName="scala.sys.process.ProcessImpl#CompoundProcess.getExitValue" problemName=DirectMissingMethodProblem + }, + { + matchName="scala.reflect.runtime.SynchronizedOps.scala$reflect$runtime$SynchronizedOps$$super$newMappedBaseTypeSeq" + problemName=ReversedMissingMethodProblem + }, + { + matchName="scala.reflect.runtime.SynchronizedOps#SynchronizedBaseTypeSeq.lateMap" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.immutable.HashMap.contains0" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.immutable.HashMap#HashTrieMap.contains0" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.immutable.HashMap#HashMap1.contains0" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.immutable.HashMap#HashMapCollision1.contains0" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps.unzip" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps.unzip3" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofFloat.unzip" + problemName=IncompatibleMethTypeProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofFloat.unzip3" + problemName=IncompatibleMethTypeProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofBoolean.unzip" + problemName=IncompatibleMethTypeProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofBoolean.unzip3" + problemName=IncompatibleMethTypeProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofRef.unzip" + problemName=IncompatibleMethTypeProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofRef.unzip3" + problemName=IncompatibleMethTypeProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofUnit.unzip" + problemName=IncompatibleMethTypeProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofUnit.unzip3" + problemName=IncompatibleMethTypeProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofDouble.unzip" + problemName=IncompatibleMethTypeProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofDouble.unzip3" + problemName=IncompatibleMethTypeProblem + }, + // see SI-8200 + { + matchName="scala.reflect.api.StandardLiftables#StandardLiftableInstances.liftTree" + problemName=MissingMethodProblem + }, + // see SI-8331 + { + matchName="scala.reflect.api.Internals#ReificationSupportApi#SyntacticTypeAppliedExtractor.unapply" + problemName=IncompatibleResultTypeProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi#SyntacticTypeAppliedExtractor.unapply" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticSelectType" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticAppliedType" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticSelectTerm" + problemName=MissingMethodProblem + }, + // see SI-8366 + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticPartialFunction" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Mirror.symbolOf" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Mirror.typeOf" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Mirror.weakTypeOf" + problemName=MissingMethodProblem + }, + // see SI-8388 + { + matchName="scala.reflect.api.Internals$ReificationSupportApi$SyntacticIdentExtractor" + problemName=MissingClassProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticIdent" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticSingletonType" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticTermIdent" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticTypeIdent" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticCompoundType" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticAnnotatedType" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticTypeProjection" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticExistentialType" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.runtime.SynchronizedOps.newNestedScope" + problemName=MissingMethodProblem + }, + // https://github.com/scala/scala/pull/3848 -- SI-8680 + { + matchName="scala.collection.immutable.Stream.scala$collection$immutable$Stream$$loop$6" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.immutable.Stream.scala$collection$immutable$Stream$$loop$5" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.immutable.Stream.scala$collection$immutable$Stream$$loop$4" + problemName=MissingMethodProblem + }, + // SI-8946 + { + matchName="scala.reflect.runtime.ThreadLocalStorage#MyThreadLocalStorage.values" + problemName=MissingMethodProblem + }, + // the below method was the unused private (sic!) method but the compatibility checker was complaining about it + { + matchName="scala.reflect.io.ZipArchive.scala$reflect$io$ZipArchive$$walkIterator" + problemName=MissingMethodProblem + }, + // SI-8362: AbstractPromise extends AtomicReference + // It's ok to change a package-protected class in an impl package, + // even though it's not clear why it changed -- bug in generic signature generation? + // -public class scala.concurrent.impl.Promise$DefaultPromise<T> extends scala.concurrent.impl.AbstractPromise implements scala.concurrent.impl.Promise<T> + // +public class scala.concurrent.impl.Promise$DefaultPromise<T extends java.lang.Object> extends scala.concurrent.impl.AbstractPromise implements scala.concurrent.impl.Promise<T> + { + matchName="scala.concurrent.impl.Promise$DefaultPromise" + problemName=MissingTypesProblem + }, + // SI-9488: Due to SI-8362 above, toString was silently changed to the AtomicReference toString implementation, + // This is fixed by SI-9488, and this should be safe since the class in question is stdlib internal. + { + matchName="scala.concurrent.impl.Promise.toString" + problemName=MissingMethodProblem + }, + // https://github.com/scala/scala/pull/5652 + { + matchName="scala.collection.mutable.ArrayOps#ofChar.slice" + problemName=FinalMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofShort.slice" + problemName=FinalMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofUnit.slice" + problemName=FinalMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofInt.slice" + problemName=FinalMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofBoolean.slice" + problemName=FinalMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofDouble.slice" + problemName=FinalMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofRef.slice" + problemName=FinalMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofByte.slice" + problemName=FinalMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofLong.slice" + problemName=FinalMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofFloat.slice" + problemName=FinalMethodProblem } ] } diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf index 533f1b2467..fdd0f0fa22 100644 --- a/bincompat-forward.whitelist.conf +++ b/bincompat-forward.whitelist.conf @@ -42,6 +42,395 @@ filter { { matchName="scala.util.hashing.MurmurHash3.wrappedArrayHash" problemName=DirectMissingMethodProblem + }, + { + matchName="scala.reflect.runtime.SynchronizedOps.newMappedBaseTypeSeq" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.reflect.runtime.JavaUniverse.newMappedBaseTypeSeq" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.immutable.HashMap.contains0" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.immutable.HashMap#HashTrieMap.contains0" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.immutable.HashMap#HashMap1.contains0" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.immutable.HashMap#HashMapCollision1.contains0" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.reflect.api.SerializedTypeTag.serialVersionUID" + problemName=MissingFieldProblem + }, + { + matchName="scala.collection.mutable.ArrayOps$ofChar" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofChar.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofChar.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps$ofShort" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofShort.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofShort.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofByte.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofByte.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofBoolean.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofBoolean.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofChar.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofChar.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofDouble.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofDouble.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps$ofUnit" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofUnit.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofUnit.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofInt.sliceImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofInt.emptyImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps$ofInt" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofInt.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofInt.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofRef.sliceImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofRef.emptyImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofChar.sliceImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofChar.emptyImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofUnit.sliceImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofUnit.emptyImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps$ofBoolean" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofBoolean.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofBoolean.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofShort.sliceImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofShort.emptyImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofShort.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofShort.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofRef.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofRef.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofUnit.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofUnit.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofByte.sliceImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofByte.emptyImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofDouble.sliceImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofDouble.emptyImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOpsImpl" + problemName=MissingClassProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofInt.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofInt.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps$ofDouble" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofDouble.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofDouble.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps$ofRef" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofRef.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofRef.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofLong.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofLong.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps$ofByte" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofByte.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofByte.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofFloat.sliceImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofFloat.emptyImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofLong.sliceImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofLong.emptyImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofBoolean.sliceImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofBoolean.emptyImpl$extension" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray$ofByte" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.WrappedArray$ofBoolean" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.WrappedArray$ofChar" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.WrappedArray$ofDouble" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.WrappedArray$ofShort" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.WrappedArray$ofRef" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.WrappedArray$ofUnit" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.WrappedArray$ofInt" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.WrappedArrayImpl" + problemName=MissingClassProblem + }, + { + matchName="scala.collection.mutable.WrappedArray$ofLong" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.WrappedArray$ofFloat" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofFloat.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.WrappedArray#ofFloat.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps$ofLong" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofLong.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofLong.emptyImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps$ofFloat" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofFloat.sliceImpl" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofFloat.emptyImpl" + problemName=DirectMissingMethodProblem + }, + // introduce FilteredTraversableInternal + { + matchName="scala.collection.immutable.Nil$" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.immutable.FilteredTraversableInternal" + problemName=MissingClassProblem + }, + { + matchName="scala.collection.immutable.List" + problemName=MissingTypesProblem + }, + { + matchName="scala.collection.immutable.$colon$colon" + problemName=MissingTypesProblem + }, + { + matchName="scala.annotation.showAsInfix$" + problemName=MissingClassProblem + }, + { + matchName="scala.annotation.showAsInfix" + problemName=MissingClassProblem + }, + { + matchName="scala.util.PropertiesTrait.coloredOutputEnabled" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.util.Properties.coloredOutputEnabled" + problemName=DirectMissingMethodProblem } ] } @@ -32,6 +32,7 @@ * - to modularize the Scala compiler or library further */ +import scala.build._ import VersionUtil._ // Scala dependencies: diff --git a/project/BuildSettings.scala b/project/BuildSettings.scala index 76cd888a2d..8456f91f86 100644 --- a/project/BuildSettings.scala +++ b/project/BuildSettings.scala @@ -1,3 +1,5 @@ +package scala.build + import sbt._ /** This object defines keys that should be visible with an unqualified name in all .sbt files and the command line */ diff --git a/project/GenerateAnyVals.scala b/project/GenerateAnyVals.scala index 84454cb0ed..f349bfd16b 100644 --- a/project/GenerateAnyVals.scala +++ b/project/GenerateAnyVals.scala @@ -1,3 +1,5 @@ +package scala.build + /** Code generation of the AnyVal types and their companions. */ trait GenerateAnyValReps { self: GenerateAnyVals => diff --git a/project/JarJar.scala b/project/JarJar.scala index 918060c9ee..3cb9e4cfff 100644 --- a/project/JarJar.scala +++ b/project/JarJar.scala @@ -1,3 +1,5 @@ +package scala.build + import org.pantsbuild.jarjar import org.pantsbuild.jarjar._ import org.pantsbuild.jarjar.util._ diff --git a/project/MiMa.scala b/project/MiMa.scala index ceda8f5594..fb9bb175ab 100644 --- a/project/MiMa.scala +++ b/project/MiMa.scala @@ -1,3 +1,5 @@ +package scala.build + // It would be nice to use sbt-mima-plugin here, but the plugin is missing // at least two features we need: // * ability to run MiMa twice, swapping `curr` and `prev`, to detect diff --git a/project/Osgi.scala b/project/Osgi.scala index 082fd91ed1..b05751958a 100644 --- a/project/Osgi.scala +++ b/project/Osgi.scala @@ -1,3 +1,5 @@ +package scala.build + import aQute.bnd.osgi.Builder import aQute.bnd.osgi.Constants._ import java.util.Properties diff --git a/project/ParserUtil.scala b/project/ParserUtil.scala index cdaf8831a5..bbd9129dbe 100644 --- a/project/ParserUtil.scala +++ b/project/ParserUtil.scala @@ -1,3 +1,5 @@ +package scala.build + import sbt._ import sbt.complete.Parser._ import sbt.complete.Parsers._ diff --git a/project/PartestUtil.scala b/project/PartestUtil.scala index 7343c1857f..127dcafefa 100644 --- a/project/PartestUtil.scala +++ b/project/PartestUtil.scala @@ -1,3 +1,5 @@ +package scala.build + import sbt._ import sbt.complete._, Parser._, Parsers._ @@ -64,9 +66,9 @@ object PartestUtil { } val matchingFileName = try { val filter = GlobFilter("*" + x + "*") - testFiles.allTestCases.filter(x => filter.accept(x._1.name)) + testFiles.allTestCases.filter(x => filter.accept(x._1.asFile.getPath)) } catch { - case t: Throwable => Nil + case _: Throwable => Nil } (matchingFileContent ++ matchingFileName).map(_._2).distinct.sorted } @@ -90,6 +92,6 @@ object PartestUtil { val ScalacOptsParser = (token("-Dpartest.scalac_opts=") ~ token(NotSpace)) map { case opt ~ v => opt + v } val P = oneOf(knownUnaryOptions.map(x => token(x))) | SrcPath | TestPathParser | Grep | ScalacOptsParser - (Space ~> repsep(P, oneOrMore(Space))).map(_.mkString(" ")).?.map(_.getOrElse("")) <~ OptSpace + (Space ~> repsep(P, oneOrMore(Space))).map(_.mkString(" ")).?.map(_.getOrElse("")) } } diff --git a/project/Quiet.scala b/project/Quiet.scala index 0a186d8f28..8ae08ad5a6 100644 --- a/project/Quiet.scala +++ b/project/Quiet.scala @@ -1,3 +1,5 @@ +package scala.build + import sbt._ import Keys._ diff --git a/project/ScalaOptionParser.scala b/project/ScalaOptionParser.scala index 27ed1f0e6f..0208921959 100644 --- a/project/ScalaOptionParser.scala +++ b/project/ScalaOptionParser.scala @@ -1,3 +1,5 @@ +package scala.build + import ParserUtil._ import sbt._ import sbt.complete.Parser._ diff --git a/project/ScalaTool.scala b/project/ScalaTool.scala index 98e18235c4..ace547c640 100644 --- a/project/ScalaTool.scala +++ b/project/ScalaTool.scala @@ -1,3 +1,5 @@ +package scala.build + import sbt._ import org.apache.commons.lang3.SystemUtils import org.apache.commons.lang3.StringUtils.replaceEach diff --git a/project/ScriptCommands.scala b/project/ScriptCommands.scala index 8d5d09943a..f6b700f007 100644 --- a/project/ScriptCommands.scala +++ b/project/ScriptCommands.scala @@ -1,3 +1,5 @@ +package scala.build + import sbt._ import Keys._ import BuildSettings.autoImport._ diff --git a/project/VersionUtil.scala b/project/VersionUtil.scala index 7c4909697f..ebc2488345 100644 --- a/project/VersionUtil.scala +++ b/project/VersionUtil.scala @@ -1,3 +1,5 @@ +package scala.build + import sbt._ import Keys._ import java.util.Properties diff --git a/scripts/jobs/integrate/bootstrap b/scripts/jobs/integrate/bootstrap index 3933854e4f..71936abf71 100755 --- a/scripts/jobs/integrate/bootstrap +++ b/scripts/jobs/integrate/bootstrap @@ -178,8 +178,7 @@ sbtResolve() { 'show update' >> $baseDir/logs/resolution 2>&1 } -# Oh boy... can't use scaladoc to document scala-xml/scala-parser-combinators -# if scaladoc depends on the same version of scala-xml/scala-parser-combinators. +# Oh boy... can't use scaladoc to document scala-xml if scaladoc depends on the same version of scala-xml. # Even if that version is available through the project's resolvers, sbt won't look past this project. # SOOOOO, we set the version to a dummy (-DOC), generate documentation, # then set the version to the right one and publish (which won't re-gen the docs). @@ -216,17 +215,6 @@ buildXML() { fi } -buildParsers() { - if [ "$PARSERS_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.modules" "scala-parser-combinators" $PARSERS_VER ) - then echo "Found scala-parser-combinators $PARSERS_VER; not building." - else - update scala scala-parser-combinators "$PARSERS_REF" && gfxd - doc="$(docTask $PARSERS_BUILT)" - sbtBuild 'set version := "'$PARSERS_VER'-DOC"' $clean "$doc" 'set version := "'$PARSERS_VER'"' test "${buildTasks[@]}" - PARSERS_BUILT="yes" - fi -} - buildPartest() { if [ "$PARTEST_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.modules" "scala-partest" $PARTEST_VER ) then echo "Found scala-partest $PARTEST_VER; not building." @@ -238,17 +226,6 @@ buildPartest() { fi } -buildSwing() { - if [ "$SWING_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.modules" "scala-swing" $SWING_VER ) - then echo "Found scala-swing $SWING_VER; not building." - else - update scala scala-swing "$SWING_REF" && gfxd - doc="$(docTask $SWING_BUILT)" - sbtBuild 'set version := "'$SWING_VER'"' $clean "$doc" test "${buildTasks[@]}" - SWING_BUILT="yes" - fi -} - # should only be called with publishTasks publishing to private-repo buildScalaCheck(){ if [ "$SCALACHECK_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scalacheck" "scalacheck" $SCALACHECK_VER ) @@ -266,8 +243,6 @@ buildModules() { publishTasks=('set credentials += Credentials(Path.userHome / ".credentials-private-repo")' "set every publishTo := Some(\"private-repo\" at \"$releaseTempRepoUrl\")") buildTasks=($publishPrivateTask) buildXML - buildParsers - buildSwing # buildScalaCheck buildPartest } @@ -276,8 +251,6 @@ buildPublishedModules() { publishTasks=('set credentials += Credentials(Path.userHome / ".credentials-sonatype")' "set pgpPassphrase := Some(Array.empty)") buildTasks=($publishSonatypeTaskModules) buildXML - buildParsers - buildSwing buildPartest } @@ -381,36 +354,26 @@ deriveModuleVersions() { if [ "$moduleVersioning" == "versions.properties" ]; then # use versions.properties as defaults when no version specified on the command line XML_VER=${XML_VER-$scala_xml_version_number} - PARSERS_VER=${PARSERS_VER-$scala_parser_combinators_version_number} - SWING_VER=${SWING_VER-$scala_swing_version_number} PARTEST_VER=${PARTEST_VER-$partest_version_number} SCALACHECK_VER=${SCALACHECK_VER-$scalacheck_version_number} XML_REF="v$XML_VER" - PARSERS_REF="v$PARSERS_VER" - SWING_REF="v$SWING_VER" PARTEST_REF="v$PARTEST_VER" SCALACHECK_REF="$SCALACHECK_VER" # no `v` in their tags else # use HEAD as default when no revision is specified on the command line XML_REF=${XML_REF-"HEAD"} - PARSERS_REF=${PARSERS_REF-"HEAD"} - SWING_REF=${SWING_REF-"HEAD"} PARTEST_REF=${PARTEST_REF-"HEAD"} SCALACHECK_REF=${SCALACHECK_REF-"HEAD"} XML_VER=$(deriveVersion scala scala-xml "$XML_REF") - PARSERS_VER=$(deriveVersion scala scala-parser-combinators "$PARSERS_REF") - SWING_VER=$(deriveVersion scala scala-swing "$SWING_REF") PARTEST_VER=$(deriveVersion scala scala-partest "$PARTEST_REF") SCALACHECK_VER=$(deriveVersionAnyTag rickynils scalacheck "$SCALACHECK_REF") fi echo "Module versions (versioning strategy: $moduleVersioning):" - echo "PARSERS = $PARSERS_VER at $PARSERS_REF" echo "PARTEST = $PARTEST_VER at $PARTEST_REF" # echo "SCALACHECK = $SCALACHECK_VER at $SCALACHECK_REF" - echo "SWING = $SWING_VER at $SWING_REF" echo "XML = $XML_VER at $XML_REF" } @@ -444,8 +407,6 @@ constructUpdatedModuleVersions() { # force the new module versions for building the core. these may be different from the values in versions.properties, # either because the variables (XML_VER) were provided, or because we're building the modules from HEAD. # in the common case, the values are the same as in versions.properties. - updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala-parser-combinators.version.number=$PARSERS_VER") - updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala-swing.version.number=$SWING_VER") updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala-xml.version.number=$XML_VER") updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dpartest.version.number=$PARTEST_VER") diff --git a/spec/05-classes-and-objects.md b/spec/05-classes-and-objects.md index 75620f57d4..5bd520589d 100644 --- a/spec/05-classes-and-objects.md +++ b/spec/05-classes-and-objects.md @@ -597,10 +597,12 @@ overridden in subclasses. A `final` class may not be inherited by a template. `final` is redundant for object definitions. Members of final classes or objects are implicitly also final, so the `final` modifier is generally redundant for them, too. Note, however, that -[constant value definitions](04-basic-declarations-and-definitions.html#value-declarations-and-definitions) do require -an explicit `final` modifier, even if they are defined in a final class or -object. `final` may not be applied to incomplete members, and it may not be -combined in one modifier list with `sealed`. +[constant value definitions](04-basic-declarations-and-definitions.html#value-declarations-and-definitions) +do require an explicit `final` modifier, +even if they are defined in a final class or object. +`final` is permitted for abstract classes +but it may not be applied to traits or incomplete members, +and it may not be combined in one modifier list with `sealed`. ### `sealed` The `sealed` modifier applies to class definitions. A @@ -709,7 +711,7 @@ Here, value parameter may not form part of the types of any of the parent classes or members of the class template $t$. It is illegal to define two formal value parameters with the same name. - If no formal parameter sections are given, an empty parameter section `()` is assumed. + If a class has no formal parameter section that is not implicit, an empty parameter section `()` is assumed. If a formal parameter declaration $x: T$ is preceded by a `val` or `var` keyword, an accessor (getter) [definition](04-basic-declarations-and-definitions.html#variable-declarations-and-definitions) @@ -842,12 +844,13 @@ TmplDef ::= ‘case’ ‘class’ ClassDef If a class definition is prefixed with `case`, the class is said to be a _case class_. -The formal parameters in the first parameter section of a case class -are called _elements_; they are treated -specially. First, the value of such a parameter can be extracted as a +A case class is required to have a parameter section that is not implicit. +The formal parameters in the first parameter section +are called _elements_ and are treated specially. +First, the value of such a parameter can be extracted as a field of a constructor pattern. Second, a `val` prefix is -implicitly added to such a parameter, unless the parameter carries -already a `val` or `var` modifier. Hence, an accessor +implicitly added to such a parameter, unless the parameter already carries +a `val` or `var` modifier. Hence, an accessor definition for the parameter is [generated](#class-definitions). A case class definition of `$c$[$\mathit{tps}\,$]($\mathit{ps}_1\,$)$\ldots$($\mathit{ps}_n$)` with type diff --git a/spec/README.md b/spec/README.md index b19ce6441f..ad524dfdf3 100644 --- a/spec/README.md +++ b/spec/README.md @@ -8,7 +8,11 @@ Third, we'd like to support different output formats. An html page per chapter w ## Editing -We use Jekyll 2 and [Redcarpet](https://github.com/vmg/redcarpet) to generate the html. Essentially, this is what github pages use. +At the time of writing we are using Jekyll 3.3.0 and [Redcarpet 3.3.2](https://github.com/vmg/redcarpet) to generate the html. + +Check `Gemfile` for the current versions. + +We aim to track the configuration GitHub Pages use but at times differences will arise as GitHub Pages evolves. ## Building diff --git a/src/compiler/scala/tools/nsc/CompileServer.scala b/src/compiler/scala/tools/nsc/CompileServer.scala index 9cac497a85..ffe95ba9dc 100644 --- a/src/compiler/scala/tools/nsc/CompileServer.scala +++ b/src/compiler/scala/tools/nsc/CompileServer.scala @@ -47,7 +47,7 @@ class StandardCompileServer(fixPort: Int = 0) extends SocketServer(fixPort) { } def printMemoryStats() { - def mb(bytes: Long) = "%dMB".format(bytes / 1000000) + def mb(bytes: Long) = "%10.2fMB".format(bytes / 1048576.0) info("New session: total memory = %s, max memory = %s, free memory = %s".format( mb(totalMemory), mb(maxMemory), mb(freeMemory))) } diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 873a5947ed..c1b0733895 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -989,7 +989,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) ) private def formatExplain(pairs: (String, Any)*): String = ( - pairs.toList collect { case (k, v) if v != null => "%20s: %s".format(k, v) } mkString "\n" + pairs collect { case (k, v) if v != null => f"$k%20s: $v" } mkString "\n" ) /** Don't want to introduce new errors trying to report errors, @@ -1002,9 +1002,10 @@ class Global(var currentSettings: Settings, var reporter: Reporter) val site = lastSeenContext.enclClassOrMethod.owner val pos_s = if (tree.pos.isDefined) s"line ${tree.pos.line} of ${tree.pos.source.file}" else "<unknown>" val context_s = try { + import scala.reflect.io.{File => SFile} // Taking 3 before, 3 after the fingered line. - val start = 0 max (tree.pos.line - 3) - val xs = scala.reflect.io.File(tree.pos.source.file.file).lines drop start take 7 + val start = 1 max (tree.pos.line - 3) + val xs = SFile(tree.pos.source.file.file).lines.drop(start-1).take(7) val strs = xs.zipWithIndex map { case (line, idx) => f"${start + idx}%6d $line" } strs.mkString("== Source file context for tree position ==\n\n", "\n", "") } @@ -1197,7 +1198,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) first } - // --------------- Miscellania ------------------------------- + // --------------- Miscellanea ------------------------------- /** Progress tracking. Measured in "progress units" which are 1 per * compilation unit per phase completed. diff --git a/src/compiler/scala/tools/nsc/PhaseAssembly.scala b/src/compiler/scala/tools/nsc/PhaseAssembly.scala index ef9818c62d..df72c37e53 100644 --- a/src/compiler/scala/tools/nsc/PhaseAssembly.scala +++ b/src/compiler/scala/tools/nsc/PhaseAssembly.scala @@ -17,7 +17,7 @@ trait PhaseAssembly { self: Global => /** - * Aux datastructure for solving the constraint system + * Aux data structure for solving the constraint system * The dependency graph container with helper methods for node and edge creation */ private class DependencyGraph { diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index cf66e0a7dc..0cdba861a5 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1263,8 +1263,8 @@ self => case CHARLIT => in.charVal case INTLIT => in.intVal(isNegated).toInt case LONGLIT => in.intVal(isNegated) - case FLOATLIT => in.floatVal(isNegated).toFloat - case DOUBLELIT => in.floatVal(isNegated) + case FLOATLIT => in.floatVal(isNegated) + case DOUBLELIT => in.doubleVal(isNegated) case STRINGLIT | STRINGPART => in.strVal.intern() case TRUE => true case FALSE => false @@ -2236,31 +2236,57 @@ self => * }}} */ def paramClauses(owner: Name, contextBounds: List[Tree], ofCaseClass: Boolean): List[List[ValDef]] = { - var implicitmod = 0 - var caseParam = ofCaseClass - def paramClause(): List[ValDef] = { - if (in.token == RPAREN) - return Nil - - if (in.token == IMPLICIT) { - in.nextToken() - implicitmod = Flags.IMPLICIT - } - commaSeparated(param(owner, implicitmod, caseParam )) - } - val vds = new ListBuffer[List[ValDef]] + var implicitSection = -1 + var implicitOffset = -1 + var warnAt = -1 + var caseParam = ofCaseClass + val vds = new ListBuffer[List[ValDef]] val start = in.offset + def paramClause(): List[ValDef] = if (in.token == RPAREN) Nil else { + val implicitmod = + if (in.token == IMPLICIT) { + if (implicitOffset == -1) { implicitOffset = in.offset ; implicitSection = vds.length } + else if (warnAt == -1) warnAt = in.offset + in.nextToken() + Flags.IMPLICIT + } else 0 + commaSeparated(param(owner, implicitmod, caseParam)) + } newLineOptWhenFollowedBy(LPAREN) - if (ofCaseClass && in.token != LPAREN) - syntaxError(in.lastOffset, "case classes without a parameter list are not allowed;\n"+ - "use either case objects or case classes with an explicit `()' as a parameter list.") - while (implicitmod == 0 && in.token == LPAREN) { + while (in.token == LPAREN) { in.nextToken() vds += paramClause() accept(RPAREN) caseParam = false newLineOptWhenFollowedBy(LPAREN) } + if (ofCaseClass) { + if (vds.isEmpty) + syntaxError(start, s"case classes must have a parameter list; try 'case class ${owner.encoded + }()' or 'case object ${owner.encoded}'") + else if (vds.head.nonEmpty && vds.head.head.mods.isImplicit) { + if (settings.isScala213) + syntaxError(start, s"case classes must have a non-implicit parameter list; try 'case class ${ + owner.encoded}()${ vds.map(vs => "(...)").mkString }'") + else { + deprecationWarning(start, s"case classes should have a non-implicit parameter list; adapting to 'case class ${ + owner.encoded}()${ vds.map(vs => "(...)").mkString }'", "2.12.2") + vds.insert(0, List.empty[ValDef]) + vds(1) = vds(1).map(vd => copyValDef(vd)(mods = vd.mods & ~Flags.CASEACCESSOR)) + if (implicitSection != -1) implicitSection += 1 + } + } + } + if (implicitSection != -1 && implicitSection != vds.length - 1) + syntaxError(implicitOffset, "an implicit parameter section must be last") + if (warnAt != -1) + syntaxError(warnAt, "multiple implicit parameter sections are not allowed") + else if (settings.warnExtraImplicit) { + // guard against anomalous class C(private implicit val x: Int)(implicit s: String) + val ttl = vds.count { case ValDef(mods, _, _, _) :: _ => mods.isImplicit ; case _ => false } + if (ttl > 1) + warning(in.offset, s"$ttl parameter sections are effectively implicit") + } val result = vds.toList if (owner == nme.CONSTRUCTOR && (result.isEmpty || (result.head take 1 exists (_.mods.isImplicit)))) { in.token match { diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index a8cc7f91c2..3ed1570c1c 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -386,6 +386,17 @@ trait Scanners extends ScannersCommon { next copyFrom this this copyFrom prev } + } else if (token == COMMA) { + // SIP-27 Trailing Comma (multi-line only) support + // If a comma is followed by a new line & then a closing paren, bracket or brace + // then it is a trailing comma and is ignored + val saved = new ScannerData {} copyFrom this + fetchToken() + if (afterLineEnd() && (token == RPAREN || token == RBRACKET || token == RBRACE)) { + /* skip the trailing comma */ + } else if (token == EOF) { // e.g. when the REPL is parsing "val List(x, y, _*," + /* skip the trailing comma */ + } else this copyFrom saved } // print("["+this+"]") @@ -972,23 +983,45 @@ trait Scanners extends ScannersCommon { def intVal: Long = intVal(negated = false) - /** Convert current strVal, base to double value + private val zeroFloat = raw"[0.]+(?:[eE][+-]?[0-9]+)?[fFdD]?".r + + /** Convert current strVal, base to float value. */ - def floatVal(negated: Boolean): Double = { - val limit: Double = if (token == DOUBLELIT) Double.MaxValue else Float.MaxValue + def floatVal(negated: Boolean): Float = { try { - val value: Double = java.lang.Double.valueOf(strVal).doubleValue() - if (value > limit) + val value: Float = java.lang.Float.parseFloat(strVal) + if (value > Float.MaxValue) syntaxError("floating point number too large") + if (value == 0.0f && !zeroFloat.pattern.matcher(strVal).matches) + syntaxError("floating point number too small") if (negated) -value else value } catch { case _: NumberFormatException => syntaxError("malformed floating point number") + 0.0f + } + } + + def floatVal: Float = floatVal(negated = false) + + /** Convert current strVal, base to double value. + */ + def doubleVal(negated: Boolean): Double = { + try { + val value: Double = java.lang.Double.parseDouble(strVal) + if (value > Double.MaxValue) + syntaxError("double precision floating point number too large") + if (value == 0.0d && !zeroFloat.pattern.matcher(strVal).matches) + syntaxError("double precision floating point number too small") + if (negated) -value else value + } catch { + case _: NumberFormatException => + syntaxError("malformed double precision floating point number") 0.0 } } - def floatVal: Double = floatVal(negated = false) + def doubleVal: Double = doubleVal(negated = false) def checkNoLetter(): Unit = { if (isIdentifierPart(ch) && ch >= ' ') diff --git a/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala index 1982c7f643..402dc66a7f 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala @@ -33,7 +33,7 @@ object AsmUtils { final val traceClassPattern = "" /** - * Print the bytedcode of classes as they are serialized by the ASM library. The serialization + * Print the bytecode of classes as they are serialized by the ASM library. The serialization * performed by `asm.ClassWriter` can change the code generated by GenBCode. For example, it * introduces stack map frames, it computes the maximal stack sizes, and it replaces dead * code by NOPs (see also https://github.com/scala/scala/pull/3726#issuecomment-42861780). diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index c7952ffe94..76d042ce3b 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -918,7 +918,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { (args zip params) filterNot isTrivial } - // first push *all* arguments. This makes sure muliple uses of the same labelDef-var will all denote the (previous) value. + // first push *all* arguments. This makes sure multiple uses of the same labelDef-var will all denote the (previous) value. aps foreach { case (arg, param) => genLoad(arg, locals(param).tk) } // `locals` is known to contain `param` because `genDefDef()` visited `labelDefsAtOrUnder` // second assign one by one to the LabelDef's variables. diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala index 18e7500172..a74c70a684 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala @@ -188,7 +188,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters { * Data for emitting an EnclosingMethod attribute. None if `classSym` is a member class (not * an anonymous or local class). See doc in BTypes. * - * The class is parametrized by two functions to obtain a bytecode class descriptor for a class + * The class is parameterized by two functions to obtain a bytecode class descriptor for a class * symbol, and to obtain a method signature descriptor fro a method symbol. These function depend * on the implementation of GenASM / GenBCode, so they need to be passed in. */ @@ -332,7 +332,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters { failNoForwarder("companion contains its own main method (implementation restriction: no main is allowed, regardless of signature)") else if (companion.isTrait) failNoForwarder("companion is a trait") - // Now either succeeed, or issue some additional warnings for things which look like + // Now either succeed, or issue some additional warnings for things which look like // attempts to be java main methods. else (possibles exists definitions.isJavaMainMethod) || { possibles exists { m => @@ -541,9 +541,9 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters { * symbol (sym.annotations) or type (as an AnnotatedType, eliminated by erasure). * * For Scala annotations this is OK: they are stored in the pickle and ignored by the backend. - * Java annoations on the other hand are additionally emitted to the classfile in Java's format. + * Java annotations on the other hand are additionally emitted to the classfile in Java's format. * - * This means that [[Type]] instances within an AnnotaionInfo reach the backend non-erased. Examples: + * This means that [[Type]] instances within an AnnotationInfo reach the backend non-erased. Examples: * - @(javax.annotation.Resource @annotation.meta.getter) val x = 0 * Here, annotationInfo.atp is an AnnotatedType. * - @SomeAnnotation[T] val x = 0 diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala index 121091fe4f..3e3229d2c3 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala @@ -83,7 +83,7 @@ abstract class BTypes { val callsitePositions: concurrent.Map[MethodInsnNode, Position] = recordPerRunCache(TrieMap.empty) /** - * Stores callsite instructions of invocatinos annotated `f(): @inline/noinline`. + * Stores callsite instructions of invocations annotated `f(): @inline/noinline`. * Instructions are added during code generation (BCodeBodyBuilder). The maps are then queried * when building the CallGraph, every Callsite object has an annotated(No)Inline field. */ @@ -287,7 +287,7 @@ abstract class BTypes { } // The InlineInfo is built from the classfile (not from the symbol) for all classes that are NOT - // being compiled. For those classes, the info is only needed if the inliner is enabled, othewise + // being compiled. For those classes, the info is only needed if the inliner is enabled, otherwise // we can save the memory. if (!compilerSettings.optInlinerEnabled) BTypes.EmptyInlineInfo else fromClassfileAttribute getOrElse fromClassfileWithoutAttribute @@ -653,7 +653,7 @@ abstract class BTypes { * Fields in the InnerClass entries: * - inner class: the (nested) class C we are talking about * - outer class: the class of which C is a member. Has to be null for non-members, i.e. for - * local and anonymous classes. NOTE: this co-incides with the presence of an + * local and anonymous classes. NOTE: this coincides with the presence of an * EnclosingMethod attribute (see below) * - inner name: A string with the simple name of the inner class. Null for anonymous classes. * - flags: access property flags, details in JVMS, table in 4.7.6. Static flag: see @@ -702,7 +702,7 @@ abstract class BTypes { * local and anonymous classes, no matter if there is an enclosing method or not. Accordingly, the * "class" field (see below) must be always defined, while the "method" field may be null. * - * NOTE: When an EnclosingMethod attribute is requried (local and anonymous classes), the "outer" + * NOTE: When an EnclosingMethod attribute is required (local and anonymous classes), the "outer" * field in the InnerClass table must be null. * * Fields: @@ -1144,7 +1144,7 @@ object BTypes { /** * Metadata about a ClassBType, used by the inliner. * - * More information may be added in the future to enable more elaborate inlinine heuristics. + * More information may be added in the future to enable more elaborate inline heuristics. * Note that this class should contain information that can only be obtained from the ClassSymbol. * Information that can be computed from the ClassNode should be added to the call graph instead. * diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala index 84f6d87c5c..2cf5cfcb8d 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala @@ -78,7 +78,7 @@ trait BytecodeWriters { } /* - * The ASM textual representation for bytecode overcomes disadvantages of javap ouput in three areas: + * The ASM textual representation for bytecode overcomes disadvantages of javap output in three areas: * (a) pickle dingbats undecipherable to the naked eye; * (b) two constant pools, while having identical contents, are displayed differently due to physical layout. * (c) stack maps (classfile version 50 and up) are displayed in encoded form by javap, 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 e25b55e7ab..90da570f01 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala @@ -382,7 +382,8 @@ class BackendUtils[BT <: BTypes](val btypes: BT) { * but not for writing in the classfile. We let the ClassWriter recompute max's. * * NOTE 2: the maxStack value computed here may be larger than the smallest correct value - * that would allow running an analyzer, see `InstructionStackEffect.forAsmAnalysisConservative`. + * that would allow running an analyzer, see `InstructionStackEffect.forAsmAnalysis` and + * `InstructionStackEffect.maxStackGrowth`. * * NOTE 3: the implementation doesn't look at instructions that cannot be reached, it computes * the max local / stack size in the reachable code. These max's work just fine for running an diff --git a/src/compiler/scala/tools/nsc/backend/jvm/analysis/package.scala b/src/compiler/scala/tools/nsc/backend/jvm/analysis/package.scala index ef961941a0..999c686aac 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/package.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/package.scala @@ -110,7 +110,7 @@ package scala.tools.nsc.backend.jvm * - Use YourKit for finding hotspots (cpu profiling). when it comes to drilling down into the details * of a hotspot, don't pay too much attention to the percentages / time counts. * - Should also try other profilers. - * - Use timers. When a method showed up as a hotspot, i added a timer around that method, and a + * - Use timers. When a method showed up as a hotspot, I added a timer around that method, and a * second one within the method to measure specific parts. The timers slow things down, but the * relative numbers show what parts of a method are slow. * 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 a4cd8fce1e..78fc7e1ecf 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala @@ -69,7 +69,7 @@ class BoxUnbox[BT <: BTypes](val btypes: BT) { * E1: M1 only works if there's a single boxing operation. * def e1(b: Boolean) = { * val i: Integer = box(10) // 10 is stored into a new local, box operation and i removed - * val j: Integer = box(20) // 20 is stored into a new local, box operation adn j removed + * val j: Integer = box(20) // 20 is stored into a new local, box operation and j removed * val r = if (b) i else j // loads and stores of the box are eliminated, r no longer exists * unbox(r) // cannot rewrite: we don't know which local to load * } @@ -138,7 +138,7 @@ class BoxUnbox[BT <: BTypes](val btypes: BT) { * - note that the MatchError creation is dead code: local2 is never null. However, our nullness * analysis cannot identify this: it does not track nullness through tuple stores and loads. * - if we re-write the non-escaping consumers of the outer tuple, but keep the tuple allocation - * and the escaping consumer, we get the follwoing: + * and the escaping consumer, we get the following: * * load 1, load 2 * val newLocal1 = new Tuple2; load newLocal1 // stack: Tuple2 @@ -188,7 +188,7 @@ class BoxUnbox[BT <: BTypes](val btypes: BT) { var maxStackGrowth = 0 - /** Mehtod M1 for eliminating box-unbox pairs (see doc comment in the beginning of this file) */ + /** Method M1 for eliminating box-unbox pairs (see doc comment in the beginning of this file) */ def replaceBoxOperationsSingleCreation(creation: BoxCreation, finalCons: Set[BoxConsumer], boxKind: BoxKind, keepBox: Boolean): Unit = { /** * If the box is eliminated, all copy operations (loads, stores, others) of the box need to 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 78acd72dba..f2ff73c44d 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala @@ -167,7 +167,7 @@ class ByteCodeRepository[BT <: BTypes](val classPath: ClassPath, val btypes: BT) * 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`). + * polymorphic (methods `invoke` and `invokeExact` in class `MethodHandles`). * * @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. An error message is also @@ -204,8 +204,8 @@ class ByteCodeRepository[BT <: BTypes](val classPath: ClassPath, val btypes: BT) 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 + val recursionResult = findIn(c) + if (recursionResult.isDefined) return recursionResult } None } 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 9c0dfb0ee2..a740ca525c 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala @@ -285,7 +285,7 @@ class CallGraph[BT <: BTypes](val btypes: BT) { // final case class :: / final case object Nil // (l: List).map // can be inlined // we need to know that - // - the recevier is sealed + // - the receiver is sealed // - what are the children of the receiver // - all children are final // - none of the children overrides map 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 b05669ce89..518646812e 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/CopyProp.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/CopyProp.scala @@ -273,7 +273,7 @@ class CopyProp[BT <: BTypes](val btypes: BT) { } /** - * Eliminate the `numArgs` inputs of the instruction `prod` (which was eliminated). Fo + * Eliminate the `numArgs` inputs of the instruction `prod` (which was eliminated). For * each input value * - if the `prod` instruction is the single consumer, enqueue the producers of the input * - otherwise, insert a POP instruction to POP the input value @@ -465,7 +465,7 @@ class CopyProp[BT <: BTypes](val btypes: BT) { } /** - * Remove `xSTORE n; xLOAD n` paris if + * Remove `xSTORE n; xLOAD n` pairs if * - the local variable n is not used anywhere else in the method (1), and * - there are no executable instructions and no live labels (jump targets) between the two (2) * 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 16ed9da0e4..7bc4ea2392 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/InlineInfoAttribute.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/InlineInfoAttribute.scala @@ -82,7 +82,7 @@ case class InlineInfoAttribute(inlineInfo: InlineInfo) extends Attribute(InlineI } /** - * De-serialize the attribute into an InlineInfo. The attribute starts at cr.b(off), but we don't + * Deserialize the attribute into an InlineInfo. The attribute starts at cr.b(off), but we don't * need to access that array directly, we can use the `read` methods provided by the ClassReader. * * `buf` is a pre-allocated character array that is guaranteed to be long enough to hold any 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 b9f593a4d8..0ae8347dc5 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala @@ -683,7 +683,7 @@ class Inliner[BT <: BTypes](val btypes: BT) { * (A2) C and D are members of the same run-time package */ def classIsAccessible(accessed: BType, from: ClassBType): Either[OptimizerWarning, Boolean] = (accessed: @unchecked) match { - // TODO: A2 requires "same run-time package", which seems to be package + classloader (JMVS 5.3.). is the below ok? + // TODO: A2 requires "same run-time package", which seems to be package + classloader (JVMS 5.3.). is the below ok? case c: ClassBType => c.isPublic.map(_ || c.packageInternalName == from.packageInternalName) case a: ArrayBType => classIsAccessible(a.elementType, from) case _: PrimitiveBType => Right(true) @@ -725,7 +725,7 @@ class Inliner[BT <: BTypes](val btypes: BT) { * type from there (https://github.com/scala-opt/scala/issues/13). */ def memberIsAccessible(memberFlags: Int, memberDeclClass: ClassBType, memberRefClass: ClassBType, from: ClassBType): Either[OptimizerWarning, Boolean] = { - // TODO: B3 requires "same run-time package", which seems to be package + classloader (JMVS 5.3.). is the below ok? + // TODO: B3 requires "same run-time package", which seems to be package + classloader (JVMS 5.3.). is the below ok? def samePackageAsDestination = memberDeclClass.packageInternalName == from.packageInternalName def targetObjectConformsToDestinationClass = false // needs type propagation analysis, see above 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 4744cb9ab1..63360e17ff 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala @@ -125,7 +125,7 @@ class InlinerHeuristics[BT <: BTypes](val bTypes: BT) { if (callsite.isInlineAnnotated && callee.canInlineFromSource) { // By default, we only emit inliner warnings for methods annotated @inline. However, we don't // want to be unnecessarily noisy with `-opt-warnings:_`: for example, the inliner heuristic - // would attempty to inline `Function1.apply$sp$II`, as it's higher-order (the receiver is + // would attempt to inline `Function1.apply$sp$II`, as it's higher-order (the receiver is // a function), and it's concrete (forwards to `apply`). But because it's non-final, it cannot // be inlined. So we only create warnings here for methods annotated @inline. Some(Left(CalleeNotFinal( 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 65d1e20d69..9c22b09cdd 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala @@ -61,7 +61,7 @@ import scala.tools.nsc.backend.jvm.opt.BytecodeUtils._ * - empty local variable descriptors (local variables that were holding the box may become unused) * * copy propagation (replaces LOAD n to the LOAD m for the smallest m that is an alias of n) - * + enables downstrem: + * + enables downstream: * - stale stores (a stored value may not be loaded anymore) * - store-load pairs (a load n may now be right after a store n) * + NOTE: copy propagation is only executed once, in the first fixpoint loop iteration. none of diff --git a/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala index 133a656206..fbd59eb04a 100644 --- a/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala +++ b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala @@ -10,9 +10,10 @@ import java.util.function.IntFunction import java.util import java.util.Comparator -import scala.reflect.io.{AbstractFile, PlainFile} +import scala.reflect.io.{AbstractFile, PlainFile, PlainNioFile} import scala.tools.nsc.util.{ClassPath, ClassRepresentation} import FileUtils._ +import scala.collection.JavaConverters._ /** * A trait allowing to look for classpath entries in directories. It provides common logic for @@ -106,7 +107,7 @@ trait JFileDirectoryLookup[FileEntryType <: ClassRepresentation] extends Directo // as the type of `case class C(); case class D(); List(C(), D()).head`, rather than the opposite order. // On Mac, the HFS performs this sorting transparently, but on Linux the order is unspecified. // - // Note this behaviour can be enabled with in javac with `javac -XDsortfiles`, but that's only + // Note this behaviour can be enabled in javac with `javac -XDsortfiles`, but that's only // intended to improve determinism of the compiler for compiler hackers. util.Arrays.sort(listing, (o1: File, o2: File) => o1.getName.compareTo(o2.getName)) listing @@ -121,51 +122,78 @@ trait JFileDirectoryLookup[FileEntryType <: ClassRepresentation] extends Directo def asClassPathStrings: Seq[String] = Seq(dir.getPath) } -object JImageDirectoryLookup { - import java.nio.file._, java.net.URI, scala.collection.JavaConverters._ - def apply(): List[ClassPath] = { +object JrtClassPath { + import java.nio.file._, java.net.URI + def apply(): Option[ClassPath] = { try { val fs = FileSystems.getFileSystem(URI.create("jrt:/")) - val dir: Path = fs.getPath("/modules") - val modules = Files.list(dir).iterator().asScala.toList - modules.map(m => new JImageDirectoryLookup(fs, m.getFileName.toString)) + Some(new JrtClassPath(fs)) } catch { case _: ProviderNotFoundException | _: FileSystemNotFoundException => - Nil + None } } } -class JImageDirectoryLookup(fs: java.nio.file.FileSystem, module: String) extends DirectoryLookup[ClassFileEntryImpl] with NoSourcePaths { + +/** + * Implementation `ClassPath` based on the JDK 9 encapsulated runtime modules (JEP-220) + * + * https://bugs.openjdk.java.net/browse/JDK-8066492 is the most up to date reference + * for the structure of the jrt:// filesystem. + * + * The implementation assumes that no classes exist in the empty package. + */ +final class JrtClassPath(fs: java.nio.file.FileSystem) extends ClassPath with NoSourcePaths { import java.nio.file.Path, java.nio.file._ type F = Path - val dir: Path = fs.getPath("/modules/" + module) + private val dir: Path = fs.getPath("/packages") - protected def emptyFiles: Array[Path] = Array.empty - protected def getSubDir(packageDirName: String): Option[Path] = { - val packageDir = dir.resolve(packageDirName) - if (Files.exists(packageDir) && Files.isDirectory(packageDir)) Some(packageDir) - else None + // e.g. "java.lang" -> Seq("/modules/java.base") + private val packageToModuleBases: Map[String, Seq[Path]] = { + val ps = Files.newDirectoryStream(dir).iterator().asScala + def lookup(pack: Path): Seq[Path] = { + Files.list(pack).iterator().asScala.map(l => if (Files.isSymbolicLink(l)) Files.readSymbolicLink(l) else l).toList + } + ps.map(p => (p.toString.stripPrefix("/packages/"), lookup(p))).toMap } - protected def listChildren(dir: Path, filter: Option[Path => Boolean]): Array[Path] = { - import scala.collection.JavaConverters._ - val f = filter.getOrElse((p: Path) => true) - Files.list(dir).iterator().asScala.filter(f).toArray[Path] + + override private[nsc] def packages(inPackage: String): Seq[PackageEntry] = { + def matches(packageDottedName: String) = + if (packageDottedName.contains(".")) + packageOf(packageDottedName) == inPackage + else inPackage == "" + packageToModuleBases.keysIterator.filter(matches).map(PackageEntryImpl(_)).toVector + } + private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = { + if (inPackage == "") Nil + else { + packageToModuleBases.getOrElse(inPackage, Nil).flatMap(x => + Files.list(x.resolve(inPackage.replace('.', '/'))).iterator().asScala.filter(_.getFileName.toString.endsWith(".class"))).map(x => + ClassFileEntryImpl(new PlainNioFile(x))).toVector + } } - protected def getName(f: Path): String = f.getFileName.toString - protected def toAbstractFile(f: Path): AbstractFile = new scala.reflect.io.PlainNioFile(f) - protected def isPackage(f: Path): Boolean = Files.isDirectory(f) && mayBeValidPackage(f.getFileName.toString) + + override private[nsc] def list(inPackage: String): ClassPathEntries = + if (inPackage == "") ClassPathEntries(packages(inPackage), Nil) + else ClassPathEntries(packages(inPackage), classes(inPackage)) def asURLs: Seq[URL] = Seq(dir.toUri.toURL) - def asClassPathStrings: Seq[String] = asURLs.map(_.toString) + // We don't yet have a scheme to represent the JDK modules in our `-classpath`. + // java models them as entries in the new "module path", we'll probably need to follow this. + def asClassPathStrings: Seq[String] = Nil def findClassFile(className: String): Option[AbstractFile] = { - val relativePath = FileUtils.dirPath(className) + ".class" - val classFile = dir.resolve(relativePath) - if (Files.exists(classFile)) Some(new scala.reflect.io.PlainNioFile(classFile)) else None + if (!className.contains(".")) None + else { + val inPackage = packageOf(className) + packageToModuleBases.getOrElse(inPackage, Nil).iterator.flatMap{x => + val file = x.resolve(className.replace('.', '/') + ".class") + if (Files.exists(file)) new scala.reflect.io.PlainNioFile(file) :: Nil else Nil + }.take(1).toList.headOption + } } - override protected def createFileEntry(file: AbstractFile): ClassFileEntryImpl = ClassFileEntryImpl(file) - override protected def isMatchingFile(f: Path): Boolean = Files.isRegularFile(f) && f.getFileName.toString.endsWith(".class") - override private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = files(inPackage) + private def packageOf(dottedClassName: String): String = + dottedClassName.substring(0, dottedClassName.lastIndexOf(".")) } case class DirectoryClassPath(dir: File) extends JFileDirectoryLookup[ClassFileEntryImpl] with NoSourcePaths { diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 947af55724..3ef75679ee 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -276,7 +276,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { // SelectFromTypeTree otherwise. See #3567. // Select nodes can be later // converted in the typechecker to SelectFromTypeTree if the class - // turns out to be an instance ionner class instead of a static inner class. + // turns out to be an instance inner class instead of a static inner class. def typeSelect(t: Tree, name: Name) = t match { case Ident(_) | Select(_, _) => Select(t, name) case _ => SelectFromTypeTree(t, name.toTypeName) diff --git a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala index 342031b601..f1f5f37c36 100644 --- a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala @@ -7,14 +7,17 @@ package scala package tools.nsc package reporters -import java.io.{ BufferedReader, PrintWriter } -import scala.reflect.internal.util._ -import StringOps._ +import java.io.{BufferedReader, PrintWriter} +import scala.reflect.internal.util.{Position, StringOps} +import Position.formatMessage +import StringOps.{countElementsAsString => countAs, trimAllTrailingSpace => trimTrailing} /** This class implements a Reporter that displays messages on a text console. */ -class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: PrintWriter) extends AbstractReporter { - def this(settings: Settings) = this(settings, Console.in, new PrintWriter(Console.err, true)) +class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: PrintWriter, echoWriter: PrintWriter) extends AbstractReporter { + def this(settings: Settings) = this(settings, Console.in, new PrintWriter(Console.err, true), new PrintWriter(Console.out, true)) + def this(settings: Settings, reader: BufferedReader, writer: PrintWriter) = + this(settings, reader, writer, writer) /** Whether a short file name should be displayed before errors */ var shortname: Boolean = false @@ -26,47 +29,41 @@ class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: Pr private def label(severity: Severity): String = severity match { case ERROR => "error" case WARNING => "warning" - case INFO => null + case INFO => "" } - protected def clabel(severity: Severity): String = { - val label0 = label(severity) - if (label0 eq null) "" else label0 + ": " + protected def clabel(severity: Severity): String = label(severity) match { + case "" => "" + case s => s"$s: " } - /** Returns the number of errors issued totally as a string. - */ - private def getCountString(severity: Severity): String = - StringOps.countElementsAsString((severity).count, label(severity)) - /** Prints the message. */ - def printMessage(msg: String) { - writer print trimAllTrailingSpace(msg) + "\n" + def printMessage(msg: String): Unit = { + writer.println(trimTrailing(msg)) writer.flush() } - /** Prints the message with the given position indication. */ - def printMessage(posIn: Position, msg: String) { - printMessage(Position.formatMessage(posIn, msg, shortname)) - } - def print(pos: Position, msg: String, severity: Severity) { - printMessage(pos, clabel(severity) + msg) + /** Prints the message to the echoWriter, which is usually stdout. */ + override def echo(msg: String): Unit = { + echoWriter.println(trimTrailing(msg)) + echoWriter.flush() } - /** Prints the column marker of the given position. - */ - def printColumnMarker(pos: Position) = - if (pos.isDefined) { printMessage(" " * (pos.column - 1) + "^") } + /** Prints the message with the given position indication. */ + def printMessage(posIn: Position, msg: String): Unit = printMessage(formatMessage(posIn, msg, shortname)) - /** Prints the number of errors and warnings if their are non-zero. */ - def printSummary() { - if (WARNING.count > 0) printMessage(getCountString(WARNING) + " found") - if ( ERROR.count > 0) printMessage(getCountString(ERROR ) + " found") - } + def print(pos: Position, msg: String, severity: Severity): Unit = printMessage(pos, s"${clabel(severity)}${msg}") + + /** Prints the column marker of the given position. */ + def printColumnMarker(pos: Position): Unit = if (pos.isDefined) printMessage(" " * (pos.column - 1) + "^") + + /** Prints the number of warnings and errors if there are any. */ + def printSummary(): Unit = + for (k <- List(WARNING, ERROR) if k.count > 0) printMessage(s"${countAs(k.count, label(k))} found") def display(pos: Position, msg: String, severity: Severity): Unit = { val ok = severity match { - case ERROR => ERROR.count <= settings.maxerrs.value + case ERROR => ERROR.count <= settings.maxerrs.value case WARNING => WARNING.count <= settings.maxwarns.value case _ => true } @@ -74,17 +71,19 @@ class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: Pr } def displayPrompt(): Unit = { - writer.print("\na)bort, s)tack, r)esume: ") + writer.println() + writer.print("a)bort, s)tack, r)esume: ") writer.flush() if (reader != null) { - val response = reader.read().asInstanceOf[Char].toLower - if (response == 'a' || response == 's') { - (new Exception).printStackTrace() - if (response == 'a') - sys exit 1 - - writer.print("\n") - writer.flush() + reader.read match { + case 'a' | 'A' => + new Throwable().printStackTrace() + System.exit(1) + case 's' | 'S' => + new Throwable().printStackTrace() + writer.println() + writer.flush() + case _ => } } } diff --git a/src/compiler/scala/tools/nsc/settings/Warnings.scala b/src/compiler/scala/tools/nsc/settings/Warnings.scala index 839e734abc..87534656f9 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 warnExtraImplicit = BooleanSetting("-Ywarn-extra-implicit", "Warn when more than one implicit parameter section is defined.") + // 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. diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 1a4671e15f..9129478b41 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -663,10 +663,9 @@ abstract class ClassfileParser { // so have to check unsafeTypeParams.isEmpty before worrying about raw type case below, // or we'll create a boatload of needless existentials. else if (classSym.isMonomorphicType || classSym.unsafeTypeParams.isEmpty) tp - else debuglogResult(s"raw type from $classSym"){ + else debuglogResult(s"raw type from $classSym") { // raw type - existentially quantify all type parameters - val eparams = typeParamsToExistentials(classSym, classSym.unsafeTypeParams) - newExistentialType(eparams, typeRef(pre, classSym, eparams.map(_.tpeHK))) + classExistentialType(pre, classSym) } case tp => assert(sig.charAt(index) != '<', s"sig=$sig, index=$index, tp=$tp") diff --git a/src/compiler/scala/tools/nsc/transform/AccessorSynthesis.scala b/src/compiler/scala/tools/nsc/transform/AccessorSynthesis.scala index a0bba46398..e027b065ac 100644 --- a/src/compiler/scala/tools/nsc/transform/AccessorSynthesis.scala +++ b/src/compiler/scala/tools/nsc/transform/AccessorSynthesis.scala @@ -99,7 +99,7 @@ trait AccessorSynthesis extends Transform with ast.TreeDSL { } - // TODO: better way to communicate from info transform to tree transfor? + // TODO: better way to communicate from info transform to tree transform? private[this] val _bitmapInfo = perRunCaches.newMap[Symbol, BitmapInfo] private[this] val _slowPathFor = perRunCaches.newMap[Symbol, Symbol]() diff --git a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala index 855e53710b..2e7ab8a887 100644 --- a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala +++ b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala @@ -152,7 +152,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre val resTpOk = ( samResultType =:= UnitTpe || functionResultType =:= samResultType - || (isReferenceType(samResultType) && isReferenceType(functionResultType))) // yes, this is what the spec says -- no further correspondance required + || (isReferenceType(samResultType) && isReferenceType(functionResultType))) // yes, this is what the spec says -- no further correspondence required if (resTpOk && (samParamTypes corresponds functionParamTypes){ (samParamTp, funParamTp) => funParamTp =:= samParamTp || (isReferenceType(funParamTp) && isReferenceType(samParamTp) && funParamTp <:< samParamTp) }) target else { @@ -165,7 +165,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre // whenever a type in the sam's signature is (erases to) a primitive type, we must pick the sam's version, // as we don't implement the logic regarding widening that's performed by LMF -- we require =:= for primitives // - // We use the sam's type for the check whether we're dealin with a reference type, as it could be a generic type, + // We use the sam's type for the check whether we're dealing with a reference type, as it could be a generic type, // which means the function's parameter -- even if it expects a value class -- will need to be // boxed on the generic call to the sam method. diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 3ce7db35d8..f8f0c193e2 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -456,7 +456,15 @@ abstract class Erasure extends InfoTransform override def newTyper(context: Context) = new Eraser(context) class ComputeBridges(unit: CompilationUnit, root: Symbol) { - assert(phase == currentRun.erasurePhase, phase) + + class BridgesCursor(root: Symbol) extends overridingPairs.Cursor(root) { + override def parents = List(root.info.firstParent) + // Varargs bridges may need generic bridges due to the non-repeated part of the signature of the involved methods. + // The vararg bridge is generated during refchecks (probably to simplify override checking), + // but then the resulting varargs "bridge" method may itself need an actual erasure bridge. + // TODO: like javac, generate just one bridge method that wraps Seq <-> varargs and does erasure-induced casts + override def exclude(sym: Symbol) = !sym.isMethod || super.exclude(sym) + } var toBeRemoved = immutable.Set[Symbol]() val site = root.thisType @@ -464,12 +472,7 @@ abstract class Erasure extends InfoTransform val bridgeTarget = mutable.HashMap[Symbol, Symbol]() var bridges = List[Tree]() - val opc = enteringExplicitOuter { - new overridingPairs.Cursor(root) { - override def parents = List(root.info.firstParent) - override def exclude(sym: Symbol) = !sym.isMethod || super.exclude(sym) - } - } + val opc = enteringExplicitOuter { new BridgesCursor(root) } def compute(): (List[Tree], immutable.Set[Symbol]) = { while (opc.hasNext) { @@ -860,6 +863,16 @@ abstract class Erasure extends InfoTransform } } + private class DoubleDefsCursor(root: Symbol) extends Cursor(root) { + // specialized members have no type history before 'specialize', causing double def errors for curried defs + override def exclude(sym: Symbol): Boolean = ( + sym.isType + || super.exclude(sym) + || !sym.hasTypeAt(currentRun.refchecksPhase.id) + ) + override def matches(lo: Symbol, high: Symbol) = !high.isPrivate + } + /** Emit an error if there is a double definition. This can happen if: * * - A template defines two members with the same name and erased type. @@ -870,21 +883,12 @@ abstract class Erasure extends InfoTransform */ private def checkNoDoubleDefs(root: Symbol) { checkNoDeclaredDoubleDefs(root) - object opc extends Cursor(root) { - // specialized members have no type history before 'specialize', causing double def errors for curried defs - override def exclude(sym: Symbol): Boolean = ( - sym.isType - || super.exclude(sym) - || !sym.hasTypeAt(currentRun.refchecksPhase.id) - ) - override def matches(lo: Symbol, high: Symbol) = !high.isPrivate - } def isErasureDoubleDef(pair: SymbolPair) = { import pair._ log(s"Considering for erasure clash:\n$pair") !exitingRefchecks(lowType matches highType) && sameTypeAfterErasure(low, high) } - opc.iterator filter isErasureDoubleDef foreach doubleDefError + (new DoubleDefsCursor(root)).iterator filter isErasureDoubleDef foreach doubleDefError } /** Add bridge definitions to a template. This means: @@ -1060,20 +1064,21 @@ abstract class Erasure extends InfoTransform } else if (args.isEmpty && interceptedMethods(fn.symbol)) { if (poundPoundMethods.contains(fn.symbol)) { + val qual1 = preErase(qual) // This is unattractive, but without it we crash here on ().## because after // 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) + val newTree = gen.mkMethodCall(RuntimeStaticsModule, methodName, qual1 :: 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.##)) + qual1.tpe.typeSymbol match { + case UnitClass | NullClass => BLOCK(qual1, LIT(0)) + case IntClass => qual1 + case s @ (ShortClass | ByteClass | CharClass) => numericConversion(qual1, s) + case BooleanClass => If(qual1, LIT(true.##), LIT(false.##)) case LongClass => staticsCall(nme.longHash) case FloatClass => staticsCall(nme.floatHash) case DoubleClass => staticsCall(nme.doubleHash) diff --git a/src/compiler/scala/tools/nsc/transform/Fields.scala b/src/compiler/scala/tools/nsc/transform/Fields.scala index fbf1e8cec1..b2bf9fad3f 100644 --- a/src/compiler/scala/tools/nsc/transform/Fields.scala +++ b/src/compiler/scala/tools/nsc/transform/Fields.scala @@ -58,7 +58,7 @@ import symtab.Flags._ * * In the even longer term (Scala 3?), I agree with @DarkDimius that it would make sense * to hide the difference between strict and lazy vals. All vals are lazy, - * but the memoization overhead is removed when we statically know they are forced during initialiation. + * but the memoization overhead is removed when we statically know they are forced during initialization. * We could still expose the low-level field semantics through `private[this] val`s. * * In any case, the current behavior of overriding vals is pretty surprising. diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index 798cfcd072..169fe7588e 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -113,7 +113,7 @@ abstract class LambdaLift extends InfoTransform { * * For DelayedInit subclasses, constructor statements end up in the synthetic init method * instead of the constructor itself, so the access should go to the field. This method changes - * `logicallyEnclosingMember` in this case to return a temprorary symbol corresponding to that + * `logicallyEnclosingMember` in this case to return a temporary symbol corresponding to that * method. */ private def logicallyEnclosingMember(sym: Symbol): Symbol = { diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index de0db51b6c..96e2135c52 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -32,7 +32,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL with AccessorSynthes * we cannot emit PROTECTED methods in interfaces on the JVM, * but knowing that these trait methods are protected means we won't emit static forwarders. * - * JVMLS: "Methods of interfaces may have any of the flags in Table 4.6-A set + * JVMS: "Methods of interfaces may have any of the flags in Table 4.6-A set * except ACC_PROTECTED, ACC_FINAL, ACC_SYNCHRONIZED, and ACC_NATIVE (JLS §9.4)." * * TODO: can we just set the right flags from the start?? @@ -137,7 +137,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL with AccessorSynthes */ def addMember(clazz: Symbol, member: Symbol): Symbol = { debuglog(s"mixing into $clazz: ${member.defString}") - // This attachment is used to instruct the backend about which methids in traits require + // This attachment is used to instruct the backend about which methods in traits require // a static trait impl method. We remove this from the new symbol created for the method // mixed into the subclass. member.removeAttachment[NeedStaticImpl.type] diff --git a/src/compiler/scala/tools/nsc/transform/SampleTransform.scala b/src/compiler/scala/tools/nsc/transform/SampleTransform.scala index ba303f7c2b..4c1705e386 100644 --- a/src/compiler/scala/tools/nsc/transform/SampleTransform.scala +++ b/src/compiler/scala/tools/nsc/transform/SampleTransform.scala @@ -35,7 +35,7 @@ abstract class SampleTransform extends Transform { atPos(tree1.pos)( // `atPos` fills in position of its tree argument Select( // The `Select` factory method is defined in class `Trees` sup, - currentOwner.newValue( // creates a new term symbol owned by `currentowner` + currentOwner.newValue( // creates a new term symbol owned by `currentOwner` newTermName("sample"), // The standard term name creator tree1.pos))))) case _ => diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 84f47c1caa..9161786d76 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -1992,7 +1992,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { else exitingSpecialize(specializeCalls(unit).transform(tree)) // Remove the final modifier and @inline annotation from anything in the - // original class (since it's being overridden in at least onesubclass). + // original class (since it's being overridden in at least one subclass). // // We do this here so that the specialized subclasses will correctly copy // final and @inline. diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 096b6b9263..f35dd6556f 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -342,12 +342,16 @@ abstract class UnCurry extends InfoTransform * the whole tree with it. */ private def replaceElidableTree(tree: Tree): Tree = { + def elisionOf(t: Type): Tree = t.typeSymbol match { + case StringClass => Literal(Constant("")) setType t + case _ => gen.mkZero(t) + } tree match { case DefDef(_,_,_,_,_,rhs) => - val rhs1 = if (rhs == EmptyTree) rhs else Block(Nil, gen.mkZero(rhs.tpe)) setType rhs.tpe + val rhs1 = if (rhs == EmptyTree) rhs else Block(Nil, elisionOf(rhs.tpe)) setType rhs.tpe deriveDefDef(tree)(_ => rhs1) setSymbol tree.symbol setType tree.tpe case _ => - gen.mkZero(tree.tpe) setType tree.tpe + elisionOf(tree.tpe) } } @@ -363,7 +367,7 @@ abstract class UnCurry extends InfoTransform * mark the method symbol SYNCHRONIZED for bytecode generation. * * Delambdafy targets are deemed ineligible as the Delambdafy phase will - * replace `this.synchronized` with `$this.synchronzed` now that it emits + * replace `this.synchronized` with `$this.synchronized` now that it emits * all lambda impl methods as static. */ private def translateSynchronized(tree: Tree) = tree match { @@ -705,7 +709,7 @@ abstract class UnCurry extends InfoTransform // // So what we need to do is to use the pre-uncurry type when creating `l$1`, which is `c.Tree` and is // correct. Now, there are two additional problems: - // 1. when varargs and byname params are involved, the uncurry transformation desugares these special + // 1. when varargs and byname params are involved, the uncurry transformation desugars these special // cases to actual typerefs, eg: // ``` // T* ~> Seq[T] (Scala-defined varargs) diff --git a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala index cb3759e5fa..db6eac34cb 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala @@ -184,8 +184,8 @@ trait Logic extends Debugging { // push negation inside formula def negationNormalFormNot(p: Prop): Prop = p match { - case And(ops) => Or(ops.map(negationNormalFormNot)) // De'Morgan - case Or(ops) => And(ops.map(negationNormalFormNot)) // De'Morgan + case And(ops) => Or(ops.map(negationNormalFormNot)) // De Morgan + case Or(ops) => And(ops.map(negationNormalFormNot)) // De Morgan case Not(p) => negationNormalForm(p) case True => False case False => True diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala index 6fdaa79c10..dc0a457be7 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala @@ -116,8 +116,8 @@ trait MatchOptimization extends MatchTreeMaking with MatchAnalysis { case _ => } - debug.patmat("sharedPrefix: "+ sharedPrefix) - debug.patmat("suffix: "+ sharedPrefix) + debug.patmat(s"sharedPrefix: $sharedPrefix") + debug.patmat(s"suffix: $suffix") // if the shared prefix contains interesting conditions (!= True) // and the last of such interesting shared conditions reuses another treemaker's test // replace the whole sharedPrefix by a ReusingCondTreeMaker diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala index 5750f8f7e7..39971590c7 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala @@ -109,25 +109,29 @@ trait MatchTranslation { // example check: List[Int] <:< ::[Int] private def extractorStep(): TranslationStep = { - def paramType = extractor.aligner.wholeType import extractor.treeMaker - // chain a type-testing extractor before the actual extractor call - // it tests the type, checks the outer pointer and casts to the expected type - // TODO: the outer check is mandated by the spec for case classes, but we do it for user-defined unapplies as well [SPEC] - // (the prefix of the argument passed to the unapply must equal the prefix of the type of the binder) - lazy val typeTest = TypeTestTreeMaker(binder, binder, paramType, paramType)(pos, extractorArgTypeTest = true) - // check whether typetest implies binder is not null, - // even though the eventual null check will be on typeTest.nextBinder - // it'll be equal to binder casted to paramType anyway (and the type test is on binder) - def extraction: TreeMaker = treeMaker(typeTest.nextBinder, typeTest impliesBinderNonNull binder, pos) // paramType = the type expected by the unapply // TODO: paramType may contain unbound type params (run/t2800, run/t3530) - val makers = ( + val makers = { + val paramType = extractor.aligner.wholeType // Statically conforms to paramType if (tpe <:< paramType) treeMaker(binder, false, pos) :: Nil - else typeTest :: extraction :: Nil - ) + else { + // chain a type-testing extractor before the actual extractor call + // it tests the type, checks the outer pointer and casts to the expected type + // TODO: the outer check is mandated by the spec for case classes, but we do it for user-defined unapplies as well [SPEC] + // (the prefix of the argument passed to the unapply must equal the prefix of the type of the binder) + val typeTest = TypeTestTreeMaker(binder, binder, paramType, paramType)(pos, extractorArgTypeTest = true) + val binderKnownNonNull = typeTest impliesBinderNonNull binder + + // check whether typetest implies binder is not null, + // even though the eventual null check will be on typeTest.nextBinder + // it'll be equal to binder casted to paramType anyway (and the type test is on binder) + typeTest :: treeMaker(typeTest.nextBinder, binderKnownNonNull, pos) :: Nil + } + } + step(makers: _*)(extractor.subBoundTrees: _*) } diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala index 89c793ec94..794d3d442a 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala @@ -564,11 +564,11 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging { else scrut match { case Typed(tree, tpt) => val suppressExhaustive = tpt.tpe hasAnnotation UncheckedClass - val supressUnreachable = tree match { + val suppressUnreachable = tree match { case Ident(name) if name startsWith nme.CHECK_IF_REFUTABLE_STRING => true // SI-7183 don't warn for withFilter's that turn out to be irrefutable. case _ => false } - val suppression = Suppression(suppressExhaustive, supressUnreachable) + val suppression = Suppression(suppressExhaustive, suppressUnreachable) val hasSwitchAnnotation = treeInfo.isSwitchAnnotation(tpt.tpe) // matches with two or fewer cases need not apply for switchiness (if-then-else will do) // `case 1 | 2` is considered as two cases. diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 2d8d591b6d..0910dca445 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -1211,7 +1211,7 @@ trait ContextErrors { "pass-by-name arguments not allowed for case class parameters" case AbstractVar => - "only classes can have declared but undefined members" + abstractVarMessage(sym) + "only traits and abstract classes can have declared but undefined members" + abstractVarMessage(sym) } issueSymbolTypeError(sym, msg) diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index fde2f7bb03..503f64a44f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -64,9 +64,8 @@ trait Contexts { self: Analyzer => for (imps <- allImportInfos.remove(unit)) { for (imp <- imps.reverse.distinct) { val used = allUsedSelectors(imp) - def isMask(s: ImportSelector) = s.name != nme.WILDCARD && s.rename == nme.WILDCARD - imp.tree.selectors filterNot (s => isMask(s) || used(s)) foreach { sel => + imp.tree.selectors filterNot (s => isMaskImport(s) || used(s)) foreach { sel => reporter.warning(imp posOf sel, "Unused import") } } @@ -74,6 +73,10 @@ trait Contexts { self: Analyzer => } } + def isMaskImport(s: ImportSelector): Boolean = s.name != nme.WILDCARD && s.rename == nme.WILDCARD + def isIndividualImport(s: ImportSelector): Boolean = s.name != nme.WILDCARD && s.rename != nme.WILDCARD + def isWildcardImport(s: ImportSelector): Boolean = s.name == nme.WILDCARD + var lastAccessCheckDetails: String = "" /** List of symbols to import from in a root context. Typically that @@ -1193,26 +1196,33 @@ trait Contexts { self: Analyzer => res } - final def lookupCompanionOf(original: Symbol): Symbol = { + final def lookupCompanionInIncompleteOwner(original: Symbol): Symbol = { + /* Search scopes in current and enclosing contexts for the definition of `symbol` */ + def lookupScopeEntry(symbol: Symbol): ScopeEntry = { + var res: ScopeEntry = null + var ctx = this + while (res == null && ctx.outer != ctx) { + val s = ctx.scope lookupSymbolEntry symbol + if (s != null) + res = s + else + ctx = ctx.outer + } + res + } + + // 1) Must be owned by the same Scope, to ensure that in + // `{ class C; { ...; object C } }`, the class is not seen as a companion of the object. + // 2) Must be a class and module symbol, so that `{ class C; def C }` or `{ type T; object T }` are not companions. lookupScopeEntry(original) match { case null => NoSymbol - case entry => entry.owner.lookupCompanion(original) + case entry => + def isCompanion(sym: Symbol): Boolean = + (original.isModule && sym.isClass || sym.isModule && original.isClass) && sym.isCoDefinedWith(original) + entry.owner.lookupNameInSameScopeAs(original, original.name.companionName).filter(isCompanion) } } - /** Search scopes in current and enclosing contexts for the definition of `symbol` */ - private def lookupScopeEntry(symbol: Symbol): ScopeEntry = { - var res: ScopeEntry = null - var ctx = this - while (res == null && ctx.outer != ctx) { - val s = ctx.scope lookupSymbolEntry symbol - if (s != null) - res = s - else - ctx = ctx.outer - } - res - } } //class Context /** A `Context` focussed on an `Import` tree */ diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala index df014b5161..ea82739504 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala @@ -240,10 +240,6 @@ abstract class Duplicators extends Analyzer { result.symbol.updateAttachment(DelambdafyTarget) result - case fun: Function => - debuglog("Clearing the type and retyping Function: " + fun) - super.typed(fun.clearType, mode, pt) - case vdef @ ValDef(mods, name, tpt, rhs) => // log("vdef fixing tpe: " + tree.tpe + " with sym: " + tree.tpe.typeSymbol + " and " + invalidSyms) //if (mods.hasFlag(Flags.LAZY)) vdef.symbol.resetFlag(Flags.MUTABLE) // Martin to Iulian: lazy vars can now appear because they are no longer boxed; Please check that deleting this statement is OK. diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index e8147dbf3a..9dd260b274 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -495,21 +495,22 @@ trait Infer extends Checkable { } /** Return inferred type arguments, given type parameters, formal parameters, - * argument types, result type and expected result type. - * If this is not possible, throw a `NoInstance` exception. - * Undetermined type arguments are represented by `definitions.NothingTpe`. - * No check that inferred parameters conform to their bounds is made here. - * - * @param tparams the type parameters of the method - * @param formals the value parameter types of the method - * @param restpe the result type of the method - * @param argtpes the argument types of the application - * @param pt the expected return type of the application - * @return @see adjustTypeArgs - * - * @throws NoInstance - */ - def methTypeArgs(tparams: List[Symbol], formals: List[Type], restpe: Type, + * argument types, result type and expected result type. + * If this is not possible, throw a `NoInstance` exception. + * Undetermined type arguments are represented by `definitions.NothingTpe`. + * No check that inferred parameters conform to their bounds is made here. + * + * @param fn the function for reporting, may be empty + * @param tparams the type parameters of the method + * @param formals the value parameter types of the method + * @param restpe the result type of the method + * @param argtpes the argument types of the application + * @param pt the expected return type of the application + * @return @see adjustTypeArgs + * + * @throws NoInstance + */ + def methTypeArgs(fn: Tree, tparams: List[Symbol], formals: List[Type], restpe: Type, argtpes: List[Type], pt: Type): AdjustedTypeArgs.Result = { val tvars = tparams map freshVar if (!sameLength(formals, argtpes)) @@ -559,21 +560,12 @@ trait Infer extends Checkable { val hasAny = pt :: restpe :: formals ::: argtpes ::: loBounds exists (_.dealiasWidenChain exists containsAny) !hasAny } - def argumentPosition(idx: Int): Position = context.tree match { - case x: ValOrDefDef => x.rhs match { - case Apply(fn, args) if idx < args.size => args(idx).pos - case _ => context.tree.pos - } - case _ => context.tree.pos - } - if (settings.warnInferAny && context.reportErrors && canWarnAboutAny) { - foreachWithIndex(targs) ((targ, idx) => - targ.typeSymbol match { - case sym @ (AnyClass | AnyValClass) => - reporter.warning(argumentPosition(idx), s"a type was inferred to be `${sym.name}`; this may indicate a programming error.") - case _ => - } - ) + if (settings.warnInferAny && context.reportErrors && !fn.isEmpty && canWarnAboutAny) { + targs.foreach(_.typeSymbol match { + case sym @ (AnyClass | AnyValClass) => + reporter.warning(fn.pos, s"a type was inferred to be `${sym.name}`; this may indicate a programming error.") + case _ => + }) } adjustTypeArgs(tparams, tvars, targs, restpe) } @@ -735,7 +727,7 @@ trait Infer extends Checkable { ) def tryInstantiating(args: List[Type]) = falseIfNoInstance { val restpe = mt resultType args - val AdjustedTypeArgs.Undets(okparams, okargs, leftUndet) = methTypeArgs(undetparams, formals, restpe, args, pt) + val AdjustedTypeArgs.Undets(okparams, okargs, leftUndet) = methTypeArgs(EmptyTree, undetparams, formals, restpe, args, pt) val restpeInst = restpe.instantiateTypeParams(okparams, okargs) // #2665: must use weak conformance, not regular one (follow the monomorphic case above) exprTypeArgs(leftUndet, restpeInst, pt, useWeaklyCompatible = true) match { @@ -989,7 +981,7 @@ trait Infer extends Checkable { val restpe = fn.tpe.resultType(argtpes) val AdjustedTypeArgs.AllArgsAndUndets(okparams, okargs, allargs, leftUndet) = - methTypeArgs(undetparams, formals, restpe, argtpes, pt) + methTypeArgs(fn, undetparams, formals, restpe, argtpes, pt) if (checkBounds(fn, NoPrefix, NoSymbol, undetparams, allargs, "inferred ")) { val treeSubst = new TreeTypeSubstituter(okparams, okargs) diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 395bda234b..28169c9da1 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1955,9 +1955,12 @@ trait Namers extends MethodSynthesis { // Doing this generally would trigger cycles; that's what we also // use the lower-level scan through the current Context as a fall back. if (!currentRun.compiles(owner)) owner.initialize - original.companionSymbol orElse { - ctx.lookupCompanionOf(original) - } + + if (original.isModuleClass) original.sourceModule + else if (!owner.isTerm && owner.hasCompleteInfo) + original.companionSymbol + else + ctx.lookupCompanionInIncompleteOwner(original) } /** A version of `Symbol#linkedClassOfClass` that works with local companions, ala `companionSymbolOf`. */ diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 296d9c6bca..31476e86cd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -189,7 +189,7 @@ abstract class RefChecks extends Transform { def varargBridge(member: Symbol, bridgetpe: Type): Tree = { log(s"Generating varargs bridge for ${member.fullLocationString} of type $bridgetpe") - val newFlags = (member.flags | VBRIDGE | ARTIFACT) & ~PRIVATE + val newFlags = (member.flags | VBRIDGE) & ~PRIVATE val bridge = member.cloneSymbolImpl(clazz, newFlags) setPos clazz.pos bridge.setInfo(bridgetpe.cloneInfo(bridge)) clazz.info.decls enter bridge @@ -1130,7 +1130,7 @@ abstract class RefChecks extends Transform { } /** Sensibility check examines flavors of equals. */ def checkSensible(pos: Position, fn: Tree, args: List[Tree]) = fn match { - case Select(qual, name @ (nme.EQ | nme.NE | nme.eq | nme.ne)) if args.length == 1 && isObjectOrAnyComparisonMethod(fn.symbol) && !currentOwner.isSynthetic => + case Select(qual, name @ (nme.EQ | nme.NE | nme.eq | nme.ne)) if args.length == 1 && isObjectOrAnyComparisonMethod(fn.symbol) && (!currentOwner.isSynthetic || currentOwner.isAnonymousFunction) => checkSensibleEquals(pos, qual, name, fn.symbol, args.head) case _ => } @@ -1158,6 +1158,7 @@ abstract class RefChecks extends Transform { } } checkUndesiredProperties(rtpe.typeSymbol, tree.pos) + checkUndesiredProperties(rtpe.typeSymbol.primaryConstructor, tree.pos) tree } diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 6d883aee3d..7943187f35 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -130,8 +130,9 @@ trait SyntheticMethods extends ast.TreeDSL { */ def canEqualMethod: Tree = { syntheticCanEqual = true - createMethod(nme.canEqual_, List(AnyTpe), BooleanTpe)(m => - Ident(m.firstParam) IS_OBJ classExistentialType(clazz)) + createMethod(nme.canEqual_, List(AnyTpe), BooleanTpe) { m => + Ident(m.firstParam) IS_OBJ classExistentialType(context.prefix, clazz) + } } /* that match { case _: this.C => true ; case _ => false } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 58a44d3ac0..65d1910364 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -864,11 +864,24 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper case _ => } debuglog(s"fallback on implicits: ${tree}/$resetTree") - val tree1 = typed(resetTree, mode) - // Q: `typed` already calls `pluginsTyped` and `adapt`. the only difference here is that - // we pass `EmptyTree` as the `original`. intended? added in 2009 (53d98e7d42) by martin. - tree1 setType pluginsTyped(tree1.tpe, this, tree1, mode, pt) - if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt, EmptyTree) + // SO-10066 Need to patch the enclosing tree in the context to make translation of Dynamic + // work during fallback typechecking below. + val resetContext: Context = { + object substResetForOriginal extends Transformer { + override def transform(tree: Tree): Tree = { + if (tree eq original) resetTree + else super.transform(tree) + } + } + context.make(substResetForOriginal.transform(context.tree)) + } + typerWithLocalContext(resetContext) { typer1 => + val tree1 = typer1.typed(resetTree, mode) + // Q: `typed` already calls `pluginsTyped` and `adapt`. the only difference here is that + // we pass `EmptyTree` as the `original`. intended? added in 2009 (53d98e7d42) by martin. + tree1 setType pluginsTyped(tree1.tpe, typer1, tree1, mode, pt) + if (tree1.isEmpty) tree1 else typer1.adapt(tree1, mode, pt, EmptyTree) + } } ) else @@ -3320,15 +3333,15 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper def handleOverloaded = { val undetparams = context.undetparams - def funArgTypes(tps: List[Type]) = tps.map { tp => - val relTp = tp.asSeenFrom(pre, fun.symbol.owner) + def funArgTypes(tpAlts: List[(Type, Symbol)]) = tpAlts.map { case (tp, alt) => + val relTp = tp.asSeenFrom(pre, alt.owner) val argTps = functionOrSamArgTypes(relTp) //println(s"funArgTypes $argTps from $relTp") argTps.map(approximateAbstracts) } - def functionProto(argTps: List[Type]): Type = - try functionType(funArgTypes(argTps).transpose.map(lub), WildcardType) + def functionProto(argTpWithAlt: List[(Type, Symbol)]): Type = + try functionType(funArgTypes(argTpWithAlt).transpose.map(lub), WildcardType) catch { case _: IllegalArgumentException => WildcardType } // To propagate as much information as possible to typedFunction, which uses the expected type to @@ -3342,21 +3355,21 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // do not receive special treatment: they are typed under WildcardType.) val altArgPts = if (settings.isScala212 && args.exists(treeInfo.isFunctionMissingParamType)) - try alts.map(alt => formalTypes(alt.info.paramTypes, argslen)).transpose // do least amount of work up front + try alts.map(alt => formalTypes(alt.info.paramTypes, argslen).map(ft => (ft, alt))).transpose // do least amount of work up front catch { case _: IllegalArgumentException => args.map(_ => Nil) } // fail safe in case formalTypes fails to align to argslen else args.map(_ => Nil) // will type under argPt == WildcardType val (args1, argTpes) = context.savingUndeterminedTypeParams() { val amode = forArgMode(fun, mode) - map2(args, altArgPts) { (arg, argPts) => + map2(args, altArgPts) { (arg, argPtAlts) => def typedArg0(tree: Tree) = { // if we have an overloaded HOF such as `(f: Int => Int)Int <and> (f: Char => Char)Char`, // and we're typing a function like `x => x` for the argument, try to collapse // the overloaded type into a single function type from which `typedFunction` // can derive the argument type for `x` in the function literal above val argPt = - if (argPts.nonEmpty && treeInfo.isFunctionMissingParamType(tree)) functionProto(argPts) + if (argPtAlts.nonEmpty && treeInfo.isFunctionMissingParamType(tree)) functionProto(argPtAlts) else WildcardType val argTyped = typedArg(tree, amode, BYVALmode, argPt) diff --git a/src/compiler/scala/tools/nsc/util/package.scala b/src/compiler/scala/tools/nsc/util/package.scala index bd95fdbb50..80e82c85d8 100644 --- a/src/compiler/scala/tools/nsc/util/package.scala +++ b/src/compiler/scala/tools/nsc/util/package.scala @@ -89,7 +89,7 @@ package object util { implicit class StackTraceOps(private val e: Throwable) extends AnyVal with StackTracing { /** Format the stack trace, returning the prefix consisting of frames that satisfy * a given predicate. - * The format is similar to the typical case described in the JavaDoc + * The format is similar to the typical case described in the Javadoc * for [[java.lang.Throwable#printStackTrace]]. * If a stack trace is truncated, it will be followed by a line of the form * `... 3 elided`, by analogy to the lines `... 3 more` which indicate diff --git a/src/compiler/scala/tools/util/PathResolver.scala b/src/compiler/scala/tools/util/PathResolver.scala index 188cabbc8d..f845656980 100644 --- a/src/compiler/scala/tools/util/PathResolver.scala +++ b/src/compiler/scala/tools/util/PathResolver.scala @@ -234,7 +234,7 @@ final class PathResolver(settings: Settings) { // Assemble the elements! def basis = List[Traversable[ClassPath]]( - JImageDirectoryLookup.apply(), // 0. The Java 9 classpath (backed by the jrt:/ virtual system) + JrtClassPath.apply(), // 0. The Java 9 classpath (backed by the jrt:/ virtual system, if available) classesInPath(javaBootClassPath), // 1. The Java bootstrap class path. contentsOfDirsInPath(javaExtDirs), // 2. The Java extension class path. classesInExpandedPath(javaUserClassPath), // 3. The Java application class path. diff --git a/src/library/rootdoc.txt b/src/library/rootdoc.txt index d78df01046..0aef41c4da 100644 --- a/src/library/rootdoc.txt +++ b/src/library/rootdoc.txt @@ -44,8 +44,7 @@ Additional parts of the standard library are shipped as separate libraries. Thes - [[scala.reflect `scala.reflect`]] - Scala's reflection API (scala-reflect.jar) - [[scala.xml `scala.xml`]] - XML parsing, manipulation, and serialization (scala-xml.jar) - [[scala.swing `scala.swing`]] - A convenient wrapper around Java's GUI framework called Swing (scala-swing.jar) - - [[scala.util.parsing `scala.util.parsing`]] - [[scala.util.parsing.combinator Parser combinators]], including an - example implementation of a [[scala.util.parsing.json JSON parser]] (scala-parser-combinators.jar) + - [[scala.util.parsing `scala.util.parsing`]] - Parser combinators (scala-parser-combinators.jar) == Automatic imports == diff --git a/src/library/scala/annotation/showAsInfix.scala b/src/library/scala/annotation/showAsInfix.scala new file mode 100644 index 0000000000..6c25e08efa --- /dev/null +++ b/src/library/scala/annotation/showAsInfix.scala @@ -0,0 +1,27 @@ +package scala.annotation + +/** + * This annotation configures how Scala prints two-parameter generic types. + * + * By default, types with symbolic names are printed infix; while types without + * them are printed using the regular generic type syntax. + * + * Example of usage: + {{{ + scala> class Map[T, U] + defined class Map + + scala> def foo: Int Map Int = ??? + foo: Map[Int,Int] + + scala> @showAsInfix class Map[T, U] + defined class Map + + scala> def foo: Int Map Int = ??? + foo: Int Map Int + }}} + * + * @param enabled whether to show this type as an infix type operator. + * @since 2.12.2 + */ +class showAsInfix(enabled: Boolean = true) extends annotation.StaticAnnotation
\ No newline at end of file diff --git a/src/library/scala/collection/BitSetLike.scala b/src/library/scala/collection/BitSetLike.scala index 209b00ebf9..f0a70170c2 100644 --- a/src/library/scala/collection/BitSetLike.scala +++ b/src/library/scala/collection/BitSetLike.scala @@ -77,26 +77,26 @@ trait BitSetLike[+This <: BitSetLike[This] with SortedSet[Int]] extends SortedSe def rangeImpl(from: Option[Int], until: Option[Int]): This = { val a = toBitMask val len = a.length - if(from.isDefined) { + if (from.isDefined) { var f = from.get var pos = 0 - while(f >= 64 && pos < len) { + while (f >= 64 && pos < len) { f -= 64 a(pos) = 0 pos += 1 } - if(f > 0 && pos < len) a(pos) &= ~((1L << f)-1) + if (f > 0 && pos < len) a(pos) &= ~((1L << f)-1) } - if(until.isDefined) { + if (until.isDefined) { val u = until.get val w = u / 64 val b = u % 64 var clearw = w+1 - while(clearw < len) { + while (clearw < len) { a(clearw) = 0 clearw += 1 } - if(w < len) a(w) &= (1L << b)-1 + if (w < len) a(w) &= (1L << b)-1 } fromBitMaskNoCopy(a) } @@ -220,7 +220,7 @@ trait BitSetLike[+This <: BitSetLike[This] with SortedSet[Int]] extends SortedSe while (i >= 0) { val wi = word(i) if (wi != 0L) return WordLength*i + 63 - java.lang.Long.numberOfLeadingZeros(wi) - i += 1 + i -= 1 } throw new NoSuchElementException("Empty BitSet") } @@ -230,7 +230,7 @@ trait BitSetLike[+This <: BitSetLike[This] with SortedSet[Int]] extends SortedSe var pre = "" val max = nwords * WordLength var i = 0 - while(i != max) { + while (i != max) { if (contains(i)) { sb append pre append i pre = sep diff --git a/src/library/scala/collection/GenTraversableLike.scala b/src/library/scala/collection/GenTraversableLike.scala index 1cd126f94f..0ee5542e30 100644 --- a/src/library/scala/collection/GenTraversableLike.scala +++ b/src/library/scala/collection/GenTraversableLike.scala @@ -249,30 +249,6 @@ trait GenTraversableLike[+A, +Repr] extends Any with GenTraversableOnce[A] with * @param bf $bfinfo * @return a new collection of type `That` which contains all elements * of this $coll followed by all elements of `that`. - * - * @usecase def ++[B](that: GenTraversableOnce[B]): $Coll[B] - * @inheritdoc - * - * Example: - * {{{ - * scala> val a = List(1) - * a: List[Int] = List(1) - * - * scala> val b = List(2) - * b: List[Int] = List(2) - * - * scala> val c = a ++ b - * c: List[Int] = List(1, 2) - * - * scala> val d = List('a') - * d: List[Char] = List(a) - * - * scala> val e = c ++ d - * e: List[AnyVal] = List(1, 2, a) - * }}} - * - * @return a new $coll which contains all elements of this $coll - * followed by all elements of `that`. */ def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That diff --git a/src/library/scala/collection/IterableLike.scala b/src/library/scala/collection/IterableLike.scala index b89720da78..419206c226 100644 --- a/src/library/scala/collection/IterableLike.scala +++ b/src/library/scala/collection/IterableLike.scala @@ -177,14 +177,14 @@ self => } /** Groups elements in fixed size blocks by passing a "sliding window" - * over them (as opposed to partitioning them, as is done in grouped.) - * "Sliding window" step is 1 by default. + * over them (as opposed to partitioning them, as is done in `grouped`.) + * The "sliding window" step is set to one. * @see [[scala.collection.Iterator]], method `sliding` * * @param size the number of elements per group * @return An iterator producing ${coll}s of size `size`, except the - * last and the only element will be truncated if there are - * fewer elements than size. + * last element (which may be the only element) will be truncated + * if there are fewer than `size` elements remaining to be grouped. */ def sliding(size: Int): Iterator[Repr] = sliding(size, 1) @@ -196,8 +196,8 @@ self => * @param step the distance between the first elements of successive * groups * @return An iterator producing ${coll}s of size `size`, except the - * last and the only element will be truncated if there are - * fewer elements than size. + * last element (which may be the only element) will be truncated + * if there are fewer than `size` elements remaining to be grouped. */ def sliding(size: Int, step: Int): Iterator[Repr] = for (xs <- iterator.sliding(size, step)) yield { diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala index d000d22f72..809e851494 100644 --- a/src/library/scala/collection/Iterator.scala +++ b/src/library/scala/collection/Iterator.scala @@ -1091,7 +1091,7 @@ trait Iterator[+A] extends TraversableOnce[A] { extends AbstractIterator[Seq[B]] with Iterator[Seq[B]] { - require(size >= 1 && step >= 1, "size=%d and step=%d, but both must be positive".format(size, step)) + require(size >= 1 && step >= 1, f"size=$size%d and step=$step%d, but both must be positive") private[this] var buffer: ArrayBuffer[B] = ArrayBuffer() // the buffer private[this] var filled = false // whether the buffer is "hot" @@ -1099,30 +1099,30 @@ trait Iterator[+A] extends TraversableOnce[A] { private[this] var pad: Option[() => B] = None // what to pad short sequences with /** Public functions which can be used to configure the iterator before use. - * - * Pads the last segment if necessary so that all segments will - * have the same size. - * - * @param x The element that will be appended to the last segment, if necessary. - * @return The same iterator, and ''not'' a new iterator. - * @note This method mutates the iterator it is called on, which can be safely used afterwards. - * @note This method is mutually exclusive with `withPartial(true)`. - */ + * + * Pads the last segment if necessary so that all segments will + * have the same size. + * + * @param x The element that will be appended to the last segment, if necessary. + * @return The same iterator, and ''not'' a new iterator. + * @note This method mutates the iterator it is called on, which can be safely used afterwards. + * @note This method is mutually exclusive with `withPartial(true)`. + */ def withPadding(x: => B): this.type = { pad = Some(() => x) this } - /** Public functions which can be used to configure the iterator before use. - * - * Select whether the last segment may be returned with less than `size` - * elements. If not, some elements of the original iterator may not be - * returned at all. - * - * @param x `true` if partial segments may be returned, `false` otherwise. - * @return The same iterator, and ''not'' a new iterator. - * @note This method mutates the iterator it is called on, which can be safely used afterwards. - * @note This method is mutually exclusive with `withPadding`. - */ + /** Public functions which can be used to configure the iterator before use. + * + * Select whether the last segment may be returned with less than `size` + * elements. If not, some elements of the original iterator may not be + * returned at all. + * + * @param x `true` if partial segments may be returned, `false` otherwise. + * @return The same iterator, and ''not'' a new iterator. + * @note This method mutates the iterator it is called on, which can be safely used afterwards. + * @note This method is mutually exclusive with `withPadding`. + */ def withPartial(x: Boolean): this.type = { _partial = x if (_partial == true) // reset pad since otherwise it will take precedence @@ -1231,9 +1231,15 @@ trait Iterator[+A] extends TraversableOnce[A] { new GroupedIterator[B](self, size, size) /** Returns an iterator which presents a "sliding window" view of - * another iterator. The first argument is the window size, and - * the second is how far to advance the window on each iteration; - * defaults to `1`. Example usages: + * this iterator. The first argument is the window size, and + * the second argument `step` is how far to advance the window + * on each iteration. The `step` defaults to `1`. + * + * The default `GroupedIterator` can be configured to either + * pad a partial result to size `size` or suppress the partial + * result entirely. + * + * Example usages: * {{{ * // Returns List(List(1, 2, 3), List(2, 3, 4), List(3, 4, 5)) * (1 to 5).iterator.sliding(3).toList @@ -1247,6 +1253,11 @@ trait Iterator[+A] extends TraversableOnce[A] { * (1 to 5).iterator.sliding(4, 3).withPadding(it2.next).toList * }}} * + * @return An iterator producing `Seq[B]`s of size `size`, except the + * last element (which may be the only element) will be truncated + * if there are fewer than `size` elements remaining to be grouped. + * This behavior can be configured. + * * @note Reuse: $consumesAndProducesIterator */ def sliding[B >: A](size: Int, step: Int = 1): GroupedIterator[B] = diff --git a/src/library/scala/collection/concurrent/TrieMap.scala b/src/library/scala/collection/concurrent/TrieMap.scala index 769d7b0dac..fe0b5c4f0e 100644 --- a/src/library/scala/collection/concurrent/TrieMap.scala +++ b/src/library/scala/collection/concurrent/TrieMap.scala @@ -932,6 +932,33 @@ extends scala.collection.concurrent.Map[K, V] if (nonReadOnly) readOnlySnapshot().iterator else new TrieMapIterator(0, this) + //////////////////////////////////////////////////////////////////////////// + // + // SI-10177 These methods need overrides as the inherited implementations + // call `.iterator` more than once, which doesn't guarantee a coherent + // view of the data if there is a concurrent writer + // Note that the we don't need overrides for keysIterator or valuesIterator + // TrieMapTest validates the behaviour. + override def values: Iterable[V] = { + if (nonReadOnly) readOnlySnapshot().values + else super.values + } + override def keySet: Set[K] = { + if (nonReadOnly) readOnlySnapshot().keySet + else super.keySet + } + override def filterKeys(p: K => Boolean): collection.Map[K, V] = { + if (nonReadOnly) readOnlySnapshot().filterKeys(p) + else super.filterKeys(p) + } + override def mapValues[W](f: V => W): collection.Map[K, W] = { + if (nonReadOnly) readOnlySnapshot().mapValues(f) + else super.mapValues(f) + } + // END extra overrides + /////////////////////////////////////////////////////////////////// + + private def cachedSize() = { val r = RDCSS_READ_ROOT() r.cachedSize(this) diff --git a/src/library/scala/collection/convert/DecorateAsJava.scala b/src/library/scala/collection/convert/DecorateAsJava.scala index 8371804b91..83fffa5940 100644 --- a/src/library/scala/collection/convert/DecorateAsJava.scala +++ b/src/library/scala/collection/convert/DecorateAsJava.scala @@ -18,91 +18,91 @@ import scala.language.implicitConversions trait DecorateAsJava extends AsJavaConverters { /** * Adds an `asJava` method that implicitly converts a Scala `Iterator` to a Java `Iterator`. - * See [[asJavaIterator]]. + * @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`. See [[asJavaEnumeration]]. + * 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`. - * See [[asJavaIterable]]. + * @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`. See [[asJavaCollection]]. + * 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`. - * See [[bufferAsJavaList]]. + * @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`. - * See [[mutableSeqAsJavaList]]. + * @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`. - * See [[seqAsJavaList]]. + * @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`. - * See [[mutableSetAsJavaSet]]. + * @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`. - * See [[setAsJavaSet]]. + * @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`. - * See [[mutableMapAsJavaMap]]. + * @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`. See [[asJavaDictionary]]. + * 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`. - * See [[mapAsJavaMap]]. + * @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`. See [[mapAsJavaConcurrentMap]]. + * 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 b74a06ece5..f680aa5267 100644 --- a/src/library/scala/collection/convert/DecorateAsScala.scala +++ b/src/library/scala/collection/convert/DecorateAsScala.scala @@ -18,70 +18,70 @@ import scala.language.implicitConversions trait DecorateAsScala extends AsScalaConverters { /** * Adds an `asScala` method that implicitly converts a Java `Iterator` to a Scala `Iterator`. - * See [[asScalaIterator]]. + * @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`. - * See [[enumerationAsScalaIterator]]. + * @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`. - * See [[iterableAsScalaIterable]]. + * @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`. - * See [[collectionAsScalaIterable]]. + * @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`. - * See [[asScalaBuffer]]. + * @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`. - * See [[asScalaSet]]. + * @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`. - * See [[mapAsScalaMap]]. + * @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`. See [[mapAsScalaConcurrentMap]]. + * 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`. - * See [[dictionaryAsScalaMap]]. + * @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]`. See [[propertiesAsScalaMap]]. + * 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/ImplicitConversions.scala b/src/library/scala/collection/convert/ImplicitConversions.scala index 747e0606c8..35e6ce1616 100644 --- a/src/library/scala/collection/convert/ImplicitConversions.scala +++ b/src/library/scala/collection/convert/ImplicitConversions.scala @@ -17,76 +17,122 @@ import JavaConverters._ /** Defines implicit converter methods from Java to Scala collections. */ trait ToScalaImplicits { - /** Implicitly converts a Java `Iterator` to a Scala `Iterator`. See [[asScalaIterator]]. */ + /** Implicitly converts a Java `Iterator` to a Scala `Iterator`. + * @see [[AsScalaConverters.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]]. */ + /** Implicitly converts a Java `Enumeration` to a Scala `Iterator`. + * @see [[AsScalaConverters.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]]. */ + /** Implicitly converts a Java `Iterable` to a Scala `Iterable`. + * @see [[AsScalaConverters.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]]. */ + /** Implicitly converts a Java `Collection` to an Scala `Iterable`. + * @see [[AsScalaConverters.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]]. */ + /** Implicitly converts a Java `List` to a Scala mutable `Buffer`. + * @see [[AsScalaConverters.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]]. */ + /** Implicitly converts a Java `Set` to a Scala mutable `Set`. + * @see [[AsScalaConverters.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]]. */ + /** Implicitly converts a Java `Map` to a Scala mutable `Map`. + * @see [[AsScalaConverters.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]]. */ + /** Implicitly converts a Java `ConcurrentMap` to a Scala mutable `ConcurrentMap`. + * @see [[AsScalaConverters.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]]. */ + /** Implicitly converts a Java `Dictionary` to a Scala mutable `Map`. + * @see [[AsScalaConverters.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]]. */ + /** Implicitly converts a Java `Properties` to a Scala `mutable Map[String, String]`. + * @see [[AsScalaConverters.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]]. */ + /** Implicitly converts a Scala `Iterator` to a Java `Iterator`. + * @see [[AsJavaConverters.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]]. */ + /** Implicitly converts a Scala `Iterator` to a Java `Enumeration`. + * @see [[AsJavaConverters.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]]. */ + /** Implicitly converts a Scala `Iterable` to a Java `Iterable`. + * @see [[AsJavaConverters.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]]. */ + /** Implicitly converts a Scala `Iterable` to an immutable Java `Collection`. + * @see [[AsJavaConverters.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]]. */ + /** Implicitly converts a Scala mutable `Buffer` to a Java `List`. + * @see [[AsJavaConverters.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]]. */ + /** Implicitly converts a Scala mutable `Seq` to a Java `List`. + * @see [[AsJavaConverters.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]]. */ + /** Implicitly converts a Scala `Seq` to a Java `List`. + * @see [[AsJavaConverters.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]]. */ + /** Implicitly converts a Scala mutable `Set` to a Java `Set`. + * @see [[AsJavaConverters.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]]. */ + /** Implicitly converts a Scala `Set` to a Java `Set`. + * @see [[AsJavaConverters.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]]. */ + /** Implicitly converts a Scala mutable `Map` to a Java `Map`. + * @see [[AsJavaConverters.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]]. */ + /** Implicitly converts a Scala mutable `Map` to a Java `Dictionary`. + * @see [[AsJavaConverters.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]]. */ + /** Implicitly converts a Scala `Map` to a Java `Map`. + * @see [[AsJavaConverters.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]]. */ + /** Implicitly converts a Scala mutable `concurrent.Map` to a Java `ConcurrentMap`. + * @see [[AsJavaConverters.mapAsJavaConcurrentMap]] + */ implicit def `map AsJavaConcurrentMap`[A, B](m: concurrent.Map[A, B]): juc.ConcurrentMap[A, B] = mapAsJavaConcurrentMap(m) } diff --git a/src/library/scala/collection/immutable/FilteredTraversableInternal.scala b/src/library/scala/collection/immutable/FilteredTraversableInternal.scala new file mode 100644 index 0000000000..35585b7826 --- /dev/null +++ b/src/library/scala/collection/immutable/FilteredTraversableInternal.scala @@ -0,0 +1,104 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala +package collection +package immutable + +import scala.annotation.tailrec + +/** + * Optimised filter functions for List + * n.b. this is an internal class to help maintain compatibility and should not be used directly. + */ +private[immutable] trait FilteredTraversableInternal[+A, +Repr <: AnyRef with TraversableLike[A, Repr]] extends TraversableLike[A, Repr] { + + // Optimized for List + + override def filter(p: A => Boolean): Self = filterImpl(p, isFlipped = false) + + override def filterNot(p: A => Boolean): Self = filterImpl(p, isFlipped = true) + + private[this] def filterImpl(p: A => Boolean, isFlipped: Boolean): Self = { + + // everything seen so far so far is not included + @tailrec def noneIn(l: Repr): Repr = { + if (l.isEmpty) + Nil.asInstanceOf[Repr] + else { + val h = l.head + val t = l.tail + if (p(h) != isFlipped) + allIn(l, t) + else + noneIn(t) + } + } + + // everything from 'start' is included, if everything from this point is in we can return the origin + // start otherwise if we discover an element that is out we must create a new partial list. + @tailrec def allIn(start: Repr, remaining: Repr): Repr = { + if (remaining.isEmpty) + start + else { + val x = remaining.head + if (p(x) != isFlipped) + allIn(start, remaining.tail) + else + partialFill(start, remaining) + } + } + + // we have seen elements that should be included then one that should be excluded, start building + def partialFill(origStart: Repr, firstMiss: Repr): Repr = { + val newHead = new ::(origStart.head, Nil) + var toProcess = origStart.tail + var currentLast = newHead + + // we know that all elements are :: until at least firstMiss.tail + while (!(toProcess eq firstMiss)) { + val newElem = new ::(toProcess.head, Nil) + currentLast.tl = newElem + currentLast = newElem + toProcess = toProcess.tail + } + + // at this point newHead points to a list which is a duplicate of all the 'in' elements up to the first miss. + // currentLast is the last element in that list. + + // now we are going to try and share as much of the tail as we can, only moving elements across when we have to. + var next = firstMiss.tail + var nextToCopy = next // the next element we would need to copy to our list if we cant share. + while (!next.isEmpty) { + // generally recommended is next.isNonEmpty but this incurs an extra method call. + val head: A = next.head + if (p(head) != isFlipped) { + next = next.tail + } else { + // its not a match - do we have outstanding elements? + while (!(nextToCopy eq next)) { + val newElem = new ::(nextToCopy.head, Nil) + currentLast.tl = newElem + currentLast = newElem + nextToCopy = nextToCopy.tail + } + nextToCopy = next.tail + next = next.tail + } + } + + // we have remaining elements - they are unchanged attach them to the end + if (!nextToCopy.isEmpty) + currentLast.tl = nextToCopy.asInstanceOf[List[A]] + + newHead.asInstanceOf[Repr] + } + + noneIn(repr) + } +}
\ No newline at end of file diff --git a/src/library/scala/collection/immutable/HashMap.scala b/src/library/scala/collection/immutable/HashMap.scala index 6b29b084aa..627f723cb0 100644 --- a/src/library/scala/collection/immutable/HashMap.scala +++ b/src/library/scala/collection/immutable/HashMap.scala @@ -52,6 +52,9 @@ sealed class HashMap[A, +B] extends AbstractMap[A, B] def get(key: A): Option[B] = get0(key, computeHash(key), 0) + override final def contains(key: A): Boolean = + contains0(key, computeHash(key), 0) + override def updated [B1 >: B] (key: A, value: B1): HashMap[A, B1] = updated0(key, computeHash(key), 0, value, null, null) @@ -92,7 +95,7 @@ sealed class HashMap[A, +B] extends AbstractMap[A, B] import HashMap.{Merger, MergeFunction, liftMerger} private[collection] def get0(key: A, hash: Int, level: Int): Option[B] = None - + protected def contains0(key: A, hash: Int, level: Int): Boolean = false private[collection] def updated0[B1 >: B](key: A, hash: Int, level: Int, value: B1, kv: (A, B1), merger: Merger[A, B1]): HashMap[A, B1] = new HashMap.HashMap1(key, hash, value, kv) @@ -185,6 +188,7 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { } } + @deprecatedInheritance("This class will be made final in a future release.", "2.12.2") class HashMap1[A,+B](private[collection] val key: A, private[collection] val hash: Int, private[collection] val value: (B @uV), private[collection] var kv: (A,B @uV)) extends HashMap[A,B] { override def size = 1 @@ -195,6 +199,8 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { override def get0(key: A, hash: Int, level: Int): Option[B] = if (hash == this.hash && key == this.key) Some(value) else None + override protected def contains0(key: A, hash: Int, level: Int): Boolean = + hash == this.hash && key == this.key private[collection] override def updated0[B1 >: B](key: A, hash: Int, level: Int, value: B1, kv: (A, B1), merger: Merger[A, B1]): HashMap[A, B1] = if (hash == this.hash && key == this.key ) { if (merger eq null) { @@ -239,6 +245,9 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { override def get0(key: A, hash: Int, level: Int): Option[B] = if (hash == this.hash) kvs.get(key) else None + override protected def contains0(key: A, hash: Int, level: Int): Boolean = + hash == this.hash && kvs.contains(key) + private[collection] override def updated0[B1 >: B](key: A, hash: Int, level: Int, value: B1, kv: (A, B1), merger: Merger[A, B1]): HashMap[A, B1] = if (hash == this.hash) { if ((merger eq null) || !kvs.contains(key)) new HashMapCollision1(hash, kvs.updated(key, value)) @@ -294,6 +303,7 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { } } + @deprecatedInheritance("This class will be made final in a future release.", "2.12.2") class HashTrieMap[A, +B]( private[collection] val bitmap: Int, private[collection] val elems: Array[HashMap[A, B @uV]], @@ -306,21 +316,41 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { override def size = size0 override def get0(key: A, hash: Int, level: Int): Option[B] = { + // Note: this code is duplicated with `contains0` + val index = (hash >>> level) & 0x1f + if (bitmap == - 1) { + elems(index).get0(key, hash, level + 5) + } else { + val mask = (1 << index) + if ((bitmap & mask) != 0) { + val offset = Integer.bitCount(bitmap & (mask - 1)) + elems(offset).get0(key, hash, level + 5) + } else { + None + } + } + } + + override protected def contains0(key: A, hash: Int, level: Int): Boolean = { + // Note: this code is duplicated from `get0` val index = (hash >>> level) & 0x1f - val mask = (1 << index) if (bitmap == - 1) { - elems(index & 0x1f).get0(key, hash, level + 5) - } else if ((bitmap & mask) != 0) { - val offset = Integer.bitCount(bitmap & (mask-1)) - elems(offset).get0(key, hash, level + 5) - } else - None + elems(index).contains0(key, hash, level + 5) + } else { + val mask = (1 << index) + if ((bitmap & mask) != 0) { + val offset = Integer.bitCount(bitmap & (mask - 1)) + elems(offset).contains0(key, hash, level + 5) + } else { + false + } + } } private[collection] override def updated0[B1 >: B](key: A, hash: Int, level: Int, value: B1, kv: (A, B1), merger: Merger[A, B1]): HashMap[A, B1] = { val index = (hash >>> level) & 0x1f val mask = (1 << index) - val offset = Integer.bitCount(bitmap & (mask-1)) + val offset = Integer.bitCount(bitmap & (mask - 1)) if ((bitmap & mask) != 0) { val sub = elems(offset) val subNew = sub.updated0(key, hash, level + 5, value, kv, merger) @@ -342,7 +372,7 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { override def removed0(key: A, hash: Int, level: Int): HashMap[A, B] = { val index = (hash >>> level) & 0x1f val mask = (1 << index) - val offset = Integer.bitCount(bitmap & (mask-1)) + val offset = Integer.bitCount(bitmap & (mask - 1)) if ((bitmap & mask) != 0) { val sub = elems(offset) val subNew = sub.removed0(key, hash, level + 5) diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala index e5444533a8..e12ce7c2eb 100644 --- a/src/library/scala/collection/immutable/List.scala +++ b/src/library/scala/collection/immutable/List.scala @@ -88,6 +88,7 @@ sealed abstract class List[+A] extends AbstractSeq[A] with Product with GenericTraversableTemplate[A, List] with LinearSeqOptimized[A, List[A]] + with FilteredTraversableInternal[A, List[A]] with scala.Serializable { override def companion: GenericCompanion[List] = List @@ -163,30 +164,41 @@ sealed abstract class List[+A] extends AbstractSeq[A] // Note to developers: there exists a duplication between this function and `reflect.internal.util.Collections#map2Conserve`. // If any successful optimization attempts or other changes are made, please rehash them there too. @tailrec - def loop(mapped: ListBuffer[B], unchanged: List[A], pending: List[A]): List[B] = - if (pending.isEmpty) { - if (mapped eq null) unchanged - else mapped.prependToList(unchanged) + def loop(mappedHead: List[B] = Nil, mappedLast: ::[B], unchanged: List[A], pending: List[A]): List[B] = + if (pending.isEmpty) { + if (mappedHead eq null) unchanged + else { + mappedLast.tl = unchanged + mappedHead } + } + else { + val head0 = pending.head + val head1 = f(head0) + + if (head1 eq head0.asInstanceOf[AnyRef]) + loop(mappedHead, mappedLast, unchanged, pending.tail) else { - val head0 = pending.head - val head1 = f(head0) - - if (head1 eq head0.asInstanceOf[AnyRef]) - loop(mapped, unchanged, pending.tail) - else { - val b = if (mapped eq null) new ListBuffer[B] else mapped - var xc = unchanged - while (xc ne pending) { - b += xc.head - xc = xc.tail - } - b += head1 - val tail0 = pending.tail - loop(b, tail0, tail0) + var xc = unchanged + var mappedHead1: List[B] = mappedHead + var mappedLast1: ::[B] = mappedLast + while (xc ne pending) { + val next = new ::[B](xc.head, Nil) + if (mappedHead1 eq null) mappedHead1 = next + if (mappedLast1 ne null) mappedLast1.tl = next + mappedLast1 = next + xc = xc.tail } + val next = new ::(head1, Nil) + if (mappedHead1 eq null) mappedHead1 = next + if (mappedLast1 ne null) mappedLast1.tl = next + mappedLast1 = next + val tail0 = pending.tail + loop(mappedHead1, mappedLast1, tail0, tail0) + } - loop(null, this, this) + } + loop(null, null, this, this) } // Overridden methods from IterableLike and SeqLike or overloaded variants of such methods @@ -402,6 +414,7 @@ sealed abstract class List[+A] extends AbstractSeq[A] // Create a proxy for Java serialization that allows us to avoid mutation // during deserialization. This is the Serialization Proxy Pattern. protected final def writeReplace(): AnyRef = new List.SerializationProxy(this) + } /** The empty list. diff --git a/src/library/scala/collection/immutable/Queue.scala b/src/library/scala/collection/immutable/Queue.scala index 1dd0d7683a..5081b39bdc 100644 --- a/src/library/scala/collection/immutable/Queue.scala +++ b/src/library/scala/collection/immutable/Queue.scala @@ -106,6 +106,15 @@ sealed class Queue[+A] protected(protected val in: List[A], protected val out: L case _ => super.:+(elem)(bf) } + override def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[Queue[A], B, That]): That = { + if (bf eq Queue.ReusableCBF) { + val thatQueue = that.asInstanceOf[Queue[B]] + new Queue[B](thatQueue.in ++ (thatQueue.out reverse_::: this.in), this.out).asInstanceOf[That] + } else { + super.++(that)(bf) + } + } + /** Creates a new queue with element added at the end * of the old queue. * @@ -116,7 +125,7 @@ sealed class Queue[+A] protected(protected val in: List[A], protected val out: L /** Returns a new queue with all elements provided by an `Iterable` object * added at the end of the queue. * - * The elements are prepended in the order they are given out by the + * The elements are appended in the order they are given out by the * iterator. * * @param iter an iterable object diff --git a/src/library/scala/collection/immutable/RedBlackTree.scala b/src/library/scala/collection/immutable/RedBlackTree.scala index afb4c9c552..4f2e9115fe 100644 --- a/src/library/scala/collection/immutable/RedBlackTree.scala +++ b/src/library/scala/collection/immutable/RedBlackTree.scala @@ -516,9 +516,10 @@ object RedBlackTree { * * According to {@see Integer#numberOfLeadingZeros} ceil(log_2(n)) = (32 - Integer.numberOfLeadingZeros(n - 1)) * - * We also don't store the deepest nodes in the path so the maximum path length is further reduced by one. + * Although we don't store the deepest nodes in the path during iteration, + * we potentially do so in `startFrom`. */ - val maximumHeight = 2 * (32 - Integer.numberOfLeadingZeros(root.count + 2 - 1)) - 2 - 1 + val maximumHeight = 2 * (32 - Integer.numberOfLeadingZeros(root.count + 2 - 1)) - 2 new Array[Tree[A, B]](maximumHeight) } private[this] var index = 0 diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala index 3d4e32971c..8f26de153a 100644 --- a/src/library/scala/collection/immutable/Stream.scala +++ b/src/library/scala/collection/immutable/Stream.scala @@ -1119,11 +1119,11 @@ object Stream extends SeqFactory[Stream] { /** Construct a stream consisting of a given first element followed by elements * from a lazily evaluated Stream. */ - def #::(hd: A): Stream[A] = cons(hd, tl) + def #::[B >: A](hd: B): Stream[B] = cons(hd, tl) /** Construct a stream consisting of the concatenation of the given stream and * a lazily evaluated Stream. */ - def #:::(prefix: Stream[A]): Stream[A] = prefix append tl + def #:::[B >: A](prefix: Stream[B]): Stream[B] = prefix append tl } /** A wrapper method that adds `#::` for cons and `#:::` for concat as operations diff --git a/src/library/scala/collection/mutable/ArrayOps.scala b/src/library/scala/collection/mutable/ArrayOps.scala index 3329e35042..5de3dad256 100644 --- a/src/library/scala/collection/mutable/ArrayOps.scala +++ b/src/library/scala/collection/mutable/ArrayOps.scala @@ -10,6 +10,8 @@ package scala package collection package mutable +import java.util + import scala.reflect.ClassTag import parallel.mutable.ParArray @@ -177,8 +179,23 @@ sealed trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomPara (a1, a2, a3) } - def seq = thisCollection +} + +/** to provide binary compat for 2.11 and 2.12 this class contains + * functionality that should be migrated to ArrayOps in 2.13 + * + */ +private[mutable] sealed trait ArrayOpsImpl[T] extends Any with ArrayOps[T] { + override final def slice(from: Int, until: Int): Array[T] = { + val start = if (from < 0) 0 else from + if (until <= start || start >= repr.length) + return emptyImpl + val end = if (until > length) length else until + sliceImpl(start, end) + } + protected def emptyImpl: Array[T] + protected def sliceImpl(from: Int, until: Int): Array[T] } @@ -189,120 +206,155 @@ sealed trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomPara */ object ArrayOps { - /** A class of `ArrayOps` for arrays containing reference types. */ - final class ofRef[T <: AnyRef](override val repr: Array[T]) extends AnyVal with ArrayOps[T] with ArrayLike[T, Array[T]] { + private val emptyByteArray = new Array[Byte](0) + private val emptyShortArray = new Array[Short](0) + private val emptyIntArray = new Array[Int](0) + private val emptyLongArray = new Array[Long](0) + private val emptyFloatArray = new Array[Float](0) + private val emptyDoubleArray = new Array[Double](0) + private val emptyUnitArray = new Array[Unit](0) + private val emptyCharArray = new Array[Char](0) + private val emptyBooleanArray = new Array[Boolean](0) + + /** A subclass of `ArrayOps` for arrays containing reference types. */ + final class ofRef[T <: AnyRef](override val repr: Array[T]) extends AnyVal with ArrayOpsImpl[T] with ArrayLike[T, Array[T]] { 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](repr.getClass.getComponentType)) + protected override def emptyImpl:Array[T] = util.Arrays.copyOf[T](repr,0) + protected override def sliceImpl(from: Int, until: Int): Array[T] = util.Arrays.copyOfRange[T](repr, from, until) def length: Int = repr.length def apply(index: Int): T = repr(index) def update(index: Int, elem: T) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `byte`s. */ -final class ofByte(override val repr: Array[Byte]) extends AnyVal with ArrayOps[Byte] with ArrayLike[Byte, Array[Byte]] { + /** A subclass of `ArrayOps` for arrays containing `Byte`s. */ + final class ofByte(override val repr: Array[Byte]) extends AnyVal with ArrayOpsImpl[Byte] with ArrayLike[Byte, Array[Byte]] { override protected[this] def thisCollection: WrappedArray[Byte] = new WrappedArray.ofByte(repr) override protected[this] def toCollection(repr: Array[Byte]): WrappedArray[Byte] = new WrappedArray.ofByte(repr) override protected[this] def newBuilder = new ArrayBuilder.ofByte + protected override def emptyImpl = emptyByteArray + protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until) def length: Int = repr.length def apply(index: Int): Byte = repr(index) def update(index: Int, elem: Byte) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `short`s. */ -final class ofShort(override val repr: Array[Short]) extends AnyVal with ArrayOps[Short] with ArrayLike[Short, Array[Short]] { + /** A subclass of `ArrayOps` for arrays containing `Short`s. */ + final class ofShort(override val repr: Array[Short]) extends AnyVal with ArrayOpsImpl[Short] with ArrayLike[Short, Array[Short]] { override protected[this] def thisCollection: WrappedArray[Short] = new WrappedArray.ofShort(repr) override protected[this] def toCollection(repr: Array[Short]): WrappedArray[Short] = new WrappedArray.ofShort(repr) override protected[this] def newBuilder = new ArrayBuilder.ofShort + protected override def emptyImpl = emptyShortArray + protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until) def length: Int = repr.length def apply(index: Int): Short = repr(index) def update(index: Int, elem: Short) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `char`s. */ -final class ofChar(override val repr: Array[Char]) extends AnyVal with ArrayOps[Char] with ArrayLike[Char, Array[Char]] { + /** A subclass of `ArrayOps` for arrays containing `Char`s. */ + final class ofChar(override val repr: Array[Char]) extends AnyVal with ArrayOpsImpl[Char] with ArrayLike[Char, Array[Char]] { override protected[this] def thisCollection: WrappedArray[Char] = new WrappedArray.ofChar(repr) override protected[this] def toCollection(repr: Array[Char]): WrappedArray[Char] = new WrappedArray.ofChar(repr) override protected[this] def newBuilder = new ArrayBuilder.ofChar + protected override def emptyImpl = emptyCharArray + protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until) def length: Int = repr.length def apply(index: Int): Char = repr(index) def update(index: Int, elem: Char) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `int`s. */ -final class ofInt(override val repr: Array[Int]) extends AnyVal with ArrayOps[Int] with ArrayLike[Int, Array[Int]] { + /** A subclass of `ArrayOps` for arrays containing `Int`s. */ + final class ofInt(override val repr: Array[Int]) extends AnyVal with ArrayOpsImpl[Int] with ArrayLike[Int, Array[Int]] { override protected[this] def thisCollection: WrappedArray[Int] = new WrappedArray.ofInt(repr) override protected[this] def toCollection(repr: Array[Int]): WrappedArray[Int] = new WrappedArray.ofInt(repr) override protected[this] def newBuilder = new ArrayBuilder.ofInt + protected override def emptyImpl = emptyIntArray + protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until) def length: Int = repr.length def apply(index: Int): Int = repr(index) def update(index: Int, elem: Int) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `long`s. */ -final class ofLong(override val repr: Array[Long]) extends AnyVal with ArrayOps[Long] with ArrayLike[Long, Array[Long]] { + /** A subclass of `ArrayOps` for arrays containing `Long`s. */ + final class ofLong(override val repr: Array[Long]) extends AnyVal with ArrayOpsImpl[Long] with ArrayLike[Long, Array[Long]] { override protected[this] def thisCollection: WrappedArray[Long] = new WrappedArray.ofLong(repr) override protected[this] def toCollection(repr: Array[Long]): WrappedArray[Long] = new WrappedArray.ofLong(repr) override protected[this] def newBuilder = new ArrayBuilder.ofLong + protected override def emptyImpl = emptyLongArray + protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until) def length: Int = repr.length def apply(index: Int): Long = repr(index) def update(index: Int, elem: Long) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `float`s. */ -final class ofFloat(override val repr: Array[Float]) extends AnyVal with ArrayOps[Float] with ArrayLike[Float, Array[Float]] { + /** A subclass of `ArrayOps` for arrays containing `Float`s. */ + final class ofFloat(override val repr: Array[Float]) extends AnyVal with ArrayOpsImpl[Float] with ArrayLike[Float, Array[Float]] { override protected[this] def thisCollection: WrappedArray[Float] = new WrappedArray.ofFloat(repr) override protected[this] def toCollection(repr: Array[Float]): WrappedArray[Float] = new WrappedArray.ofFloat(repr) override protected[this] def newBuilder = new ArrayBuilder.ofFloat + protected override def emptyImpl = emptyFloatArray + protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until) def length: Int = repr.length def apply(index: Int): Float = repr(index) def update(index: Int, elem: Float) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `double`s. */ -final class ofDouble(override val repr: Array[Double]) extends AnyVal with ArrayOps[Double] with ArrayLike[Double, Array[Double]] { + /** A subclass of `ArrayOps` for arrays containing `Double`s. */ + final class ofDouble(override val repr: Array[Double]) extends AnyVal with ArrayOpsImpl[Double] with ArrayLike[Double, Array[Double]] { override protected[this] def thisCollection: WrappedArray[Double] = new WrappedArray.ofDouble(repr) override protected[this] def toCollection(repr: Array[Double]): WrappedArray[Double] = new WrappedArray.ofDouble(repr) override protected[this] def newBuilder = new ArrayBuilder.ofDouble + protected override def emptyImpl = emptyDoubleArray + protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until) def length: Int = repr.length def apply(index: Int): Double = repr(index) def update(index: Int, elem: Double) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `boolean`s. */ -final class ofBoolean(override val repr: Array[Boolean]) extends AnyVal with ArrayOps[Boolean] with ArrayLike[Boolean, Array[Boolean]] { + /** A subclass of `ArrayOps` for arrays containing `Boolean`s. */ + final class ofBoolean(override val repr: Array[Boolean]) extends AnyVal with ArrayOpsImpl[Boolean] with ArrayLike[Boolean, Array[Boolean]] { override protected[this] def thisCollection: WrappedArray[Boolean] = new WrappedArray.ofBoolean(repr) override protected[this] def toCollection(repr: Array[Boolean]): WrappedArray[Boolean] = new WrappedArray.ofBoolean(repr) override protected[this] def newBuilder = new ArrayBuilder.ofBoolean + protected override def emptyImpl = emptyBooleanArray + protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until) def length: Int = repr.length def apply(index: Int): Boolean = repr(index) def update(index: Int, elem: Boolean) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays of `Unit` types. */ -final class ofUnit(override val repr: Array[Unit]) extends AnyVal with ArrayOps[Unit] with ArrayLike[Unit, Array[Unit]] { + /** A subclass of `ArrayOps` for arrays of `Unit` types. */ + final class ofUnit(override val repr: Array[Unit]) extends AnyVal with ArrayOpsImpl[Unit] with ArrayLike[Unit, Array[Unit]] { override protected[this] def thisCollection: WrappedArray[Unit] = new WrappedArray.ofUnit(repr) override protected[this] def toCollection(repr: Array[Unit]): WrappedArray[Unit] = new WrappedArray.ofUnit(repr) override protected[this] def newBuilder = new ArrayBuilder.ofUnit + protected override def emptyImpl = emptyUnitArray + protected override def sliceImpl(from: Int, until: Int) = { + // cant use util.Arrays.copyOfRange[Unit](repr, from, until) - Unit is special and doesnt compile + val res = new Array[Unit](until-from) + System.arraycopy(repr, from, res, 0, res.size) + res + } def length: Int = repr.length def apply(index: Int): Unit = repr(index) diff --git a/src/library/scala/collection/mutable/WrappedArray.scala b/src/library/scala/collection/mutable/WrappedArray.scala index 0b5ebe7e9a..d0919c4357 100644 --- a/src/library/scala/collection/mutable/WrappedArray.scala +++ b/src/library/scala/collection/mutable/WrappedArray.scala @@ -85,12 +85,26 @@ extends AbstractSeq[T] */ override protected[this] def newBuilder: Builder[T, WrappedArray[T]] = new WrappedArrayBuilder[T](elemTag) +} + +private[mutable] abstract class WrappedArrayImpl[T] extends WrappedArray[T] { + override def slice(from: Int, until: Int): WrappedArray[T] = { + val start = if (from < 0) 0 else from + if (until <= start || start >= repr.length) + return emptyImpl + val end = if (until > length) length else until + sliceImpl(start, end) + } + protected def emptyImpl: WrappedArray[T] + + protected def sliceImpl(from: Int, until: Int): WrappedArray[T] } /** A companion object used to create instances of `WrappedArray`. */ object WrappedArray { + import java.util // This is reused for all calls to empty. private val EmptyWrappedArray = new ofRef[AnyRef](new Array[AnyRef](0)) def empty[T <: AnyRef]: WrappedArray[T] = EmptyWrappedArray.asInstanceOf[WrappedArray[T]] @@ -124,7 +138,17 @@ 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 { + private val emptyWrappedByte = new ofByte(new Array[Byte](0)) + private val emptyWrappedShort = new ofShort(new Array[Short](0)) + private val emptyWrappedInt = new ofInt(new Array[Int](0)) + private val emptyWrappedLong = new ofLong(new Array[Long](0)) + private val emptyWrappedFloat = new ofFloat(new Array[Float](0)) + private val emptyWrappedDouble = new ofDouble(new Array[Double](0)) + private val emptyWrappedUnit = new ofUnit(new Array[Unit](0)) + private val emptyWrappedChar = new ofChar(new Array[Char](0)) + private val emptyWrappedBoolean = new ofBoolean(new Array[Boolean](0)) + + final class ofRef[T <: AnyRef](val array: Array[T]) extends WrappedArrayImpl[T] with Serializable { lazy val elemTag = ClassTag[T](array.getClass.getComponentType) def length: Int = array.length def apply(index: Int): T = array(index).asInstanceOf[T] @@ -134,9 +158,11 @@ object WrappedArray { case that: ofRef[_] => Arrays.equals(array.asInstanceOf[Array[AnyRef]], that.array.asInstanceOf[Array[AnyRef]]) case _ => super.equals(that) } + protected override def emptyImpl = new ofRef(util.Arrays.copyOf[T](array,0)) + protected override def sliceImpl(from: Int, until: Int) = new ofRef[T](util.Arrays.copyOfRange[T](array, from, until)) } - final class ofByte(val array: Array[Byte]) extends WrappedArray[Byte] with Serializable { + final class ofByte(val array: Array[Byte]) extends WrappedArrayImpl[Byte] with Serializable { def elemTag = ClassTag.Byte def length: Int = array.length def apply(index: Int): Byte = array(index) @@ -146,9 +172,11 @@ object WrappedArray { case that: ofByte => Arrays.equals(array, that.array) case _ => super.equals(that) } + protected override def emptyImpl = emptyWrappedByte + protected override def sliceImpl(from: Int, until: Int) = new ofByte(util.Arrays.copyOfRange(array, from, until)) } - final class ofShort(val array: Array[Short]) extends WrappedArray[Short] with Serializable { + final class ofShort(val array: Array[Short]) extends WrappedArrayImpl[Short] with Serializable { def elemTag = ClassTag.Short def length: Int = array.length def apply(index: Int): Short = array(index) @@ -158,9 +186,11 @@ object WrappedArray { case that: ofShort => Arrays.equals(array, that.array) case _ => super.equals(that) } + protected override def emptyImpl = emptyWrappedShort + protected override def sliceImpl(from: Int, until: Int) = new ofShort(util.Arrays.copyOfRange(array, from, until)) } - final class ofChar(val array: Array[Char]) extends WrappedArray[Char] with Serializable { + final class ofChar(val array: Array[Char]) extends WrappedArrayImpl[Char] with Serializable { def elemTag = ClassTag.Char def length: Int = array.length def apply(index: Int): Char = array(index) @@ -170,9 +200,11 @@ object WrappedArray { case that: ofChar => Arrays.equals(array, that.array) case _ => super.equals(that) } + protected override def emptyImpl = emptyWrappedChar + protected override def sliceImpl(from: Int, until: Int) = new ofChar(util.Arrays.copyOfRange(array, from, until)) } - final class ofInt(val array: Array[Int]) extends WrappedArray[Int] with Serializable { + final class ofInt(val array: Array[Int]) extends WrappedArrayImpl[Int] with Serializable { def elemTag = ClassTag.Int def length: Int = array.length def apply(index: Int): Int = array(index) @@ -182,9 +214,11 @@ object WrappedArray { case that: ofInt => Arrays.equals(array, that.array) case _ => super.equals(that) } + protected override def emptyImpl = emptyWrappedInt + protected override def sliceImpl(from: Int, until: Int) = new ofInt(util.Arrays.copyOfRange(array, from, until)) } - final class ofLong(val array: Array[Long]) extends WrappedArray[Long] with Serializable { + final class ofLong(val array: Array[Long]) extends WrappedArrayImpl[Long] with Serializable { def elemTag = ClassTag.Long def length: Int = array.length def apply(index: Int): Long = array(index) @@ -194,9 +228,11 @@ object WrappedArray { case that: ofLong => Arrays.equals(array, that.array) case _ => super.equals(that) } + protected override def emptyImpl = emptyWrappedLong + protected override def sliceImpl(from: Int, until: Int) = new ofLong(util.Arrays.copyOfRange(array, from, until)) } - final class ofFloat(val array: Array[Float]) extends WrappedArray[Float] with Serializable { + final class ofFloat(val array: Array[Float]) extends WrappedArrayImpl[Float] with Serializable { def elemTag = ClassTag.Float def length: Int = array.length def apply(index: Int): Float = array(index) @@ -206,9 +242,11 @@ object WrappedArray { case that: ofFloat => Arrays.equals(array, that.array) case _ => super.equals(that) } + protected override def emptyImpl = emptyWrappedFloat + protected override def sliceImpl(from: Int, until: Int) = new ofFloat(util.Arrays.copyOfRange(array, from, until)) } - final class ofDouble(val array: Array[Double]) extends WrappedArray[Double] with Serializable { + final class ofDouble(val array: Array[Double]) extends WrappedArrayImpl[Double] with Serializable { def elemTag = ClassTag.Double def length: Int = array.length def apply(index: Int): Double = array(index) @@ -218,9 +256,11 @@ object WrappedArray { case that: ofDouble => Arrays.equals(array, that.array) case _ => super.equals(that) } + protected override def emptyImpl = emptyWrappedDouble + protected override def sliceImpl(from: Int, until: Int) = new ofDouble(util.Arrays.copyOfRange(array, from, until)) } - final class ofBoolean(val array: Array[Boolean]) extends WrappedArray[Boolean] with Serializable { + final class ofBoolean(val array: Array[Boolean]) extends WrappedArrayImpl[Boolean] with Serializable { def elemTag = ClassTag.Boolean def length: Int = array.length def apply(index: Int): Boolean = array(index) @@ -230,9 +270,11 @@ object WrappedArray { case that: ofBoolean => Arrays.equals(array, that.array) case _ => super.equals(that) } + protected override def emptyImpl = emptyWrappedBoolean + protected override def sliceImpl(from: Int, until: Int) = new ofBoolean(util.Arrays.copyOfRange(array, from, until)) } - final class ofUnit(val array: Array[Unit]) extends WrappedArray[Unit] with Serializable { + final class ofUnit(val array: Array[Unit]) extends WrappedArrayImpl[Unit] with Serializable { def elemTag = ClassTag.Unit def length: Int = array.length def apply(index: Int): Unit = array(index) @@ -242,5 +284,14 @@ object WrappedArray { case that: ofUnit => array.length == that.array.length case _ => super.equals(that) } + protected override def emptyImpl = emptyWrappedUnit + protected override def sliceImpl(from: Int, until: Int) = { + // cant use + // new ofUnit(util.Arrays.copyOfRange[Unit](array, from, until)) - Unit is special and doesnt compile + // cant use util.Arrays.copyOfRange[Unit](repr, from, until) - Unit is special and doesnt compile + val res = new Array[Unit](until-from) + System.arraycopy(repr, from, res, 0, until-from) + new ofUnit(res) + } } } diff --git a/src/library/scala/deprecated.scala b/src/library/scala/deprecated.scala index 60f0857550..a57745dbea 100644 --- a/src/library/scala/deprecated.scala +++ b/src/library/scala/deprecated.scala @@ -39,20 +39,18 @@ import scala.annotation.meta._ * '''`@deprecated` in the Scala language and its standard library'''<br/> * * A deprecated element of the Scala language or a definition in the Scala standard library will - * be preserved or at least another major version. + * be preserved at least for the current major version. * - * This means that an element deprecated since 2.12 will be preserved in 2.13, but will very likely - * not be part of 2.14. Sometimes a deprecated element might be kept for more than a major - * release to ease migration and upgrades from older Scala versions.<br/> - * Developers should not rely on this. + * This means that an element deprecated in some 2.12.x release will be preserved in + * all 2.12.x releases, but may be removed in 2.13. (A deprecated element + * might be kept longer to ease migration. Developers should not rely on this.) * * '''Special deprecation policy for Scala 2.12'''<br> - * The Scala team has decided to enact a special deprecation policy for the 2.12 release:<br/> + * The Scala team has decided to enact a special deprecation policy for Scala 2.12:<br/> * - * As an upgrade from Scala 2.11 to Scala 2.12 also requires upgrading from Java 6 to Java 8, - * no deprecated elements will be removed in this release to ease migration and upgrades - * from older Scala versions. This means that elements deprecated since 2.11 (or earlier) - * will not be removed in Scala 2.12. + * As an upgrade from 2.11 to 2.12 also requires upgrading from Java 6 to Java 8, + * deprecated elements will not normally be removed in this release, to ease migration + * and cross-building. * * @see The official documentation on [[http://www.scala-lang.org/news/2.11.0/#binary-compatibility binary compatibility]]. * @param message the message to print during compilation if the definition is accessed diff --git a/src/library/scala/sys/process/ProcessBuilder.scala b/src/library/scala/sys/process/ProcessBuilder.scala index 8288d8d480..b7966b0341 100644 --- a/src/library/scala/sys/process/ProcessBuilder.scala +++ b/src/library/scala/sys/process/ProcessBuilder.scala @@ -186,7 +186,7 @@ trait ProcessBuilder extends Source with Sink { def lineStream(log: ProcessLogger): Stream[String] /** Deprecated (renamed). Use `lineStream(log: ProcessLogger)` instead. */ - @deprecated("use stream instead", "2.11.0") + @deprecated("use lineStream instead", "2.11.0") def lines(log: ProcessLogger): Stream[String] = lineStream(log) /** Starts the process represented by this builder. The output is returned as @@ -210,7 +210,7 @@ trait ProcessBuilder extends Source with Sink { def lineStream_!(log: ProcessLogger): Stream[String] /** Deprecated (renamed). Use `lineStream_!(log: ProcessLogger)` instead. */ - @deprecated("use stream_! instead", "2.11.0") + @deprecated("use lineStream_! instead", "2.11.0") def lines_!(log: ProcessLogger): Stream[String] = lineStream_!(log) /** Starts the process represented by this builder, blocks until it exits, and diff --git a/src/library/scala/util/Properties.scala b/src/library/scala/util/Properties.scala index 7b21351cf6..29a635fcbe 100644 --- a/src/library/scala/util/Properties.scala +++ b/src/library/scala/util/Properties.scala @@ -154,6 +154,12 @@ private[scala] trait PropertiesTrait { /* Some runtime values. */ private[scala] def isAvian = javaVmName contains "Avian" + private[scala] def coloredOutputEnabled: Boolean = propOrElse("scala.color", "auto") match { + case "auto" => System.console() != null && !isWin + case a if a.toLowerCase() == "true" => true + case _ => false + } + // This is looking for javac, tools.jar, etc. // Tries JDK_HOME first, then the more common but likely jre JAVA_HOME, // and finally the system property based javaHome. diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala index a6e584424b..8ba3e62ac2 100644 --- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala +++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala @@ -316,8 +316,9 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => /** Check whether any of the arguments mention a symbol */ def refsSymbol(sym: Symbol) = hasArgWhich(_.symbol == sym) - def stringArg(index: Int) = constantAtIndex(index) map (_.stringValue) - def intArg(index: Int) = constantAtIndex(index) map (_.intValue) + def stringArg(index: Int) = constantAtIndex(index) map (_.stringValue) + def intArg(index: Int) = constantAtIndex(index) map (_.intValue) + def booleanArg(index: Int) = constantAtIndex(index) map (_.booleanValue) def symbolArg(index: Int) = argAtIndex(index) collect { case Apply(fun, Literal(str) :: Nil) if fun.symbol == definitions.Symbol_apply => newTermName(str.stringValue) diff --git a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala index 0ef52213e5..1cdefff2e9 100644 --- a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala +++ b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala @@ -33,6 +33,9 @@ trait BaseTypeSeqs { protected def newBaseTypeSeq(parents: List[Type], elems: Array[Type]) = new BaseTypeSeq(parents, elems) + protected def newMappedBaseTypeSeq(orig: BaseTypeSeq, f: Type => Type) = + new MappedBaseTypeSeq(orig, f) + /** Note: constructor is protected to force everyone to use the factory method newBaseTypeSeq instead. * This is necessary because when run from reflection every base type sequence needs to have a * SynchronizedBaseTypeSeq as mixin. @@ -125,7 +128,7 @@ trait BaseTypeSeqs { newBaseTypeSeq(parents, arr) } - def lateMap(f: Type => Type): BaseTypeSeq = new MappedBaseTypeSeq(this, f) + def lateMap(f: Type => Type): BaseTypeSeq = newMappedBaseTypeSeq(this, f) def exists(p: Type => Boolean): Boolean = elems exists p diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 19460af27f..315af267bc 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -667,8 +667,8 @@ trait Definitions extends api.StandardDefinitions { isBundle && isBlackbox } - def isListType(tp: Type) = tp <:< classExistentialType(ListClass) - def isIterableType(tp: Type) = tp <:< classExistentialType(IterableClass) + def isListType(tp: Type) = tp.typeSymbol.isNonBottomSubClass(ListClass) + def isIterableType(tp: Type) = tp.typeSymbol.isNonBottomSubClass(IterableClass) // These "direct" calls perform no dealiasing. They are most needed when // printing types when one wants to preserve the true nature of the type. @@ -975,19 +975,15 @@ trait Definitions extends api.StandardDefinitions { } /** Given a class symbol C with type parameters T1, T2, ... Tn - * which have upper/lower bounds LB1/UB1, LB1/UB2, ..., LBn/UBn, + * which have upper/lower bounds LB1/UB1, LB2/UB2, ..., LBn/UBn, * returns an existential type of the form * - * C[E1, ..., En] forSome { E1 >: LB1 <: UB1 ... en >: LBn <: UBn }. + * C[E1, ..., En] forSome { E1 >: LB1 <: UB1 ... En >: LBn <: UBn }. */ - // TODO Review the way this is used. I see two potential problems: - // 1. `existentialAbstraction` here doesn't create fresh existential type symbols, it just - // uses the class type parameter symbols directly as the list of quantified symbols. - // See SI-8244 for the trouble that this can cause. - // Compare with callers of `typeParamsToExistentials` (used in Java raw type handling) - // 2. Why don't we require a prefix? Could its omission lead to wrong results in CheckabilityChecker? - def classExistentialType(clazz: Symbol): Type = - existentialAbstraction(clazz.typeParams, clazz.tpe_*) + def classExistentialType(prefix: Type, clazz: Symbol): Type = { + val eparams = typeParamsToExistentials(clazz, clazz.unsafeTypeParams) + newExistentialType(eparams, typeRef(prefix, clazz, eparams.map(_.tpeHK))) + } // members of class scala.Any @@ -1421,6 +1417,8 @@ trait Definitions extends api.StandardDefinitions { case _ => false } + lazy val ShowAsInfixAnnotationClass = rootMirror.getClassIfDefined("scala.annotation.showAsInfix") + // todo: reconcile with javaSignature!!! def signature(tp: Type): String = { def erasure(tp: Type): Type = tp match { diff --git a/src/reflect/scala/reflect/internal/Flags.scala b/src/reflect/scala/reflect/internal/Flags.scala index 8aa6b16e06..d5bf8b7cef 100644 --- a/src/reflect/scala/reflect/internal/Flags.scala +++ b/src/reflect/scala/reflect/internal/Flags.scala @@ -163,7 +163,7 @@ class Flags extends ModifierFlags { final val LOCKED = 1L << 39 // temporary flag to catch cyclic dependencies final val SPECIALIZED = 1L << 40 // symbol is a generated specialized member - final val VBRIDGE = 1L << 42 // symbol is a varargs bridge + final val VBRIDGE = 1L << 42 // symbol is a varargs bridge (but not a bridge at the bytecode level) final val VARARGS = 1L << 43 // symbol is a Java-style varargs method final val TRIEDCOOKING = 1L << 44 // `Cooking` has been tried on this symbol diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala index 9d39ef8b42..055f7c9d5b 100644 --- a/src/reflect/scala/reflect/internal/Names.scala +++ b/src/reflect/scala/reflect/internal/Names.scala @@ -296,11 +296,13 @@ trait Names extends api.Names { */ final def pos(s: String, start: Int): Int = { var i = pos(s.charAt(0), start) - while (i + s.length() <= len) { + val sLen = s.length() + if (sLen == 1) return i + while (i + sLen <= len) { var j = 1 while (s.charAt(j) == chrs(index + i + j)) { j += 1 - if (j == s.length()) return i + if (j == sLen) return i } i = pos(s.charAt(0), i + 1) } diff --git a/src/reflect/scala/reflect/internal/Positions.scala b/src/reflect/scala/reflect/internal/Positions.scala index 95b3b7fb14..1a1aa2e721 100644 --- a/src/reflect/scala/reflect/internal/Positions.scala +++ b/src/reflect/scala/reflect/internal/Positions.scala @@ -255,7 +255,7 @@ trait Positions extends api.Positions { self: SymbolTable => val annTrees = mdef.mods.annotations match { case Nil if mdef.symbol != null => // After typechecking, annotations are moved from the modifiers - // to the annotation on the symbol of the anotatee. + // to the annotation on the symbol of the annotatee. mdef.symbol.annotations.map(_.original) case anns => anns } diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index 9602a2859b..bb352e9d31 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -775,7 +775,7 @@ trait Printers extends api.Printers { self: SymbolTable => } // constructor's params processing (don't print single empty constructor param list) vparamss match { - case Nil | List(Nil) if (!mods.isCase && !ctorMods.hasFlag(AccessFlags)) => + case Nil | List(Nil) if !mods.isCase && !ctorMods.hasFlag(AccessFlags) => case _ => vparamss foreach printConstrParams } parents diff --git a/src/reflect/scala/reflect/internal/ReificationSupport.scala b/src/reflect/scala/reflect/internal/ReificationSupport.scala index 026438e421..21320149a3 100644 --- a/src/reflect/scala/reflect/internal/ReificationSupport.scala +++ b/src/reflect/scala/reflect/internal/ReificationSupport.scala @@ -266,7 +266,7 @@ trait ReificationSupport { self: SymbolTable => } // undo gen.mkTemplate - protected object UnMkTemplate { + protected class UnMkTemplate(isCaseClass: Boolean) { def unapply(templ: Template): Option[(List[Tree], ValDef, Modifiers, List[List[ValDef]], List[Tree], List[Tree])] = { val Template(parents, selfType, _) = templ val tbody = treeInfo.untypecheckedTemplBody(templ) @@ -296,8 +296,9 @@ trait ReificationSupport { self: SymbolTable => result(ctorMods, Nil, edefs, body) else { // undo conversion from (implicit ... ) to ()(implicit ... ) when it's the only parameter section + // except that case classes require the explicit leading empty parameter list val vparamssRestoredImplicits = ctorVparamss match { - case Nil :: (tail @ ((head :: _) :: _)) if head.mods.isImplicit => tail + case Nil :: (tail @ ((head :: _) :: _)) if head.mods.isImplicit && !isCaseClass => tail case other => other } // undo flag modifications by merging flag info from constructor args and fieldDefs @@ -314,7 +315,9 @@ trait ReificationSupport { self: SymbolTable => } } } + def asCase = new UnMkTemplate(isCaseClass = true) } + protected object UnMkTemplate extends UnMkTemplate(isCaseClass = false) protected def mkSelfType(tree: Tree) = tree match { case vd: ValDef => @@ -346,9 +349,15 @@ trait ReificationSupport { self: SymbolTable => def unapply(tree: Tree): Option[(Modifiers, TypeName, List[TypeDef], Modifiers, List[List[ValDef]], List[Tree], List[Tree], ValDef, List[Tree])] = tree match { - case ClassDef(mods, name, tparams, UnMkTemplate(parents, selfType, ctorMods, vparamss, earlyDefs, body)) - if !ctorMods.isTrait && !ctorMods.hasFlag(JAVA) => - Some((mods, name, tparams, ctorMods, vparamss, earlyDefs, parents, selfType, body)) + case ClassDef(mods, name, tparams, impl) => + val X = if (mods.isCase) UnMkTemplate.asCase else UnMkTemplate + impl match { + case X(parents, selfType, ctorMods, vparamss, earlyDefs, body) + if (!ctorMods.isTrait && !ctorMods.hasFlag(JAVA)) => + Some((mods, name, tparams, ctorMods, vparamss, earlyDefs, parents, selfType, body)) + case _ => + None + } case _ => None } diff --git a/src/reflect/scala/reflect/internal/Scopes.scala b/src/reflect/scala/reflect/internal/Scopes.scala index 19804fc5f3..0435a2c1cf 100644 --- a/src/reflect/scala/reflect/internal/Scopes.scala +++ b/src/reflect/scala/reflect/internal/Scopes.scala @@ -291,25 +291,6 @@ trait Scopes extends api.Scopes { self: SymbolTable => null } - final def lookupCompanion(original: Symbol): Symbol = { - lookupSymbolEntry(original) match { - case null => - case entry => - var e = lookupEntry(original.name.companionName) - while (e != null) { - // 1) Must be owned by the same Scope, to ensure that in - // `{ class C; { ...; object C } }`, the class is not seen as a comaniopn of the object. - // 2) Must be a class and module symbol, so that `{ class C; def C }` or `{ type T; object T }` are not companions. - def isClassAndModule(sym1: Symbol, sym2: Symbol) = sym1.isClass && sym2.isModule - if ((e.owner eq entry.owner) && (isClassAndModule(original, e.sym) || isClassAndModule(e.sym, original))) { - return if (e.sym.isCoDefinedWith(original)) e.sym else NoSymbol - } - e = lookupNextEntry(e) - } - } - NoSymbol - } - /** lookup a symbol entry matching given name. * @note from Martin: I believe this is a hotspot or will be one * in future versions of the type system. I have reverted the previous @@ -345,6 +326,20 @@ trait Scopes extends api.Scopes { self: SymbolTable => e } + final def lookupNameInSameScopeAs(original: Symbol, companionName: Name): Symbol = { + lookupSymbolEntry(original) match { + case null => + case entry => + var e = lookupEntry(companionName) + while (e != null) { + if (e.owner eq entry.owner) return e.sym + e = lookupNextEntry(e) + } + } + NoSymbol + } + + /** TODO - we can test this more efficiently than checking isSubScope * in both directions. However the size test might be enough to quickly * rule out most failures. diff --git a/src/reflect/scala/reflect/internal/TypeDebugging.scala b/src/reflect/scala/reflect/internal/TypeDebugging.scala index e9050b4e33..58359e66d9 100644 --- a/src/reflect/scala/reflect/internal/TypeDebugging.scala +++ b/src/reflect/scala/reflect/internal/TypeDebugging.scala @@ -59,7 +59,7 @@ trait TypeDebugging { object typeDebug { import scala.Console._ - private val colorsOk = sys.props contains "scala.color" + private val colorsOk = scala.util.Properties.coloredOutputEnabled private def inColor(s: String, color: String) = if (colorsOk && s != "") color + s + RESET else s private def inBold(s: String, color: String) = if (colorsOk && s != "") color + BOLD + s + RESET else s diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index ad7e3ffe8f..b46f071717 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -309,6 +309,9 @@ trait Types /** Is this type completed (i.e. not a lazy type)? */ def isComplete: Boolean = true + /** Should this be printed as an infix type (@showAsInfix class &&[T, U])? */ + def isShowAsInfixType: Boolean = false + /** If this is a lazy type, assign a new type to `sym`. */ def complete(sym: Symbol) {} @@ -2102,6 +2105,15 @@ trait Types trivial = fromBoolean(!sym.isTypeParameter && pre.isTrivial && areTrivialTypes(args)) toBoolean(trivial) } + + /* It only makes sense to show 2-ary type constructors infix. + * By default we do only if it's a symbolic name. */ + override def isShowAsInfixType: Boolean = + hasLength(args, 2) && + sym.getAnnotation(ShowAsInfixAnnotationClass) + .map(_ booleanArg 0 getOrElse true) + .getOrElse(!Character.isUnicodeIdentifierStart(sym.decodedName.head)) + private[Types] def invalidateTypeRefCaches(): Unit = { parentsCache = null parentsPeriod = NoPeriod @@ -2327,6 +2339,22 @@ trait Types case arg :: Nil => s"($arg,)" case _ => args.mkString("(", ", ", ")") } + private def infixTypeString: String = { + /* SLS 3.2.8: all infix types have the same precedence. + * In A op B op' C, op and op' need the same associativity. + * Therefore, if op is left associative, anything on its right + * needs to be parenthesized if it's an infix type, and vice versa. */ + // we should only get here after `isShowInfixType` says we have 2 args + val l :: r :: Nil = args + + val isRightAssoc = typeSymbol.decodedName endsWith ":" + + val lstr = if (isRightAssoc && l.isShowAsInfixType) s"($l)" else l.toString + + val rstr = if (!isRightAssoc && r.isShowAsInfixType) s"($r)" else r.toString + + s"$lstr ${sym.decodedName} $rstr" + } private def customToString = sym match { case RepeatedParamClass | JavaRepeatedParamClass => args.head + "*" case ByNameParamClass => "=> " + args.head @@ -2350,6 +2378,8 @@ trait Types xs.init.mkString("(", ", ", ")") + " => " + xs.last } } + else if (isShowAsInfixType) + infixTypeString else if (isTupleTypeDirect(this)) tupleTypeString else if (sym.isAliasType && prefixChain.exists(_.termSymbol.isSynthetic) && (this ne dealias)) @@ -3944,7 +3974,7 @@ trait Types * any corresponding non-variant type arguments of bt1 and bt2 are the same */ def isPopulated(tp1: Type, tp2: Type): Boolean = { - def isConsistent(tp1: Type, tp2: Type): Boolean = (tp1, tp2) match { + def isConsistent(tp1: Type, tp2: Type): Boolean = (tp1.dealias, tp2.dealias) match { case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) => assert(sym1 == sym2, (sym1, sym2)) ( pre1 =:= pre2 @@ -4152,7 +4182,7 @@ trait Types * The specification-enumerated non-value types are method types, polymorphic * method types, and type constructors. Supplements to the specified set of * non-value types include: types which wrap non-value symbols (packages - * abd statics), overloaded types. Varargs and by-name types T* and (=>T) are + * and statics), overloaded types. Varargs and by-name types T* and (=>T) are * not designated non-value types because there is code which depends on using * them as type arguments, but their precise status is unclear. */ @@ -4251,7 +4281,7 @@ trait Types case mt1 @ MethodType(params1, res1) => tp2 match { case mt2 @ MethodType(params2, res2) => - // sameLength(params1, params2) was used directly as pre-screening optimization (now done by matchesQuantified -- is that ok, performancewise?) + // sameLength(params1, params2) was used directly as pre-screening optimization (now done by matchesQuantified -- is that ok, performance-wise?) mt1.isImplicit == mt2.isImplicit && matchingParams(params1, params2, mt1.isJava, mt2.isJava) && matchesQuantified(params1, params2, res1, res2) @@ -4696,7 +4726,7 @@ trait Types case _ => Depth(1) } - //OPT replaced with tailrecursive function to save on #closures + //OPT replaced with tail recursive function to save on #closures // was: // var d = 0 // for (tp <- tps) d = d max by(tp) //!!!OPT!!! diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala index fe1de91662..08ccac8069 100644 --- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala @@ -385,7 +385,7 @@ abstract class UnPickler { // We're stuck with the order types are pickled in, but with judicious use // of named parameters we can recapture a declarative flavor in a few cases. - // But it's still a rat's nest of adhockery. + // But it's still a rat's nest of ad-hockery. (tag: @switch) match { case NOtpe => NoType case NOPREFIXtpe => NoPrefix diff --git a/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala index 108ce45cca..6d9a9d6649 100644 --- a/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala +++ b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala @@ -136,7 +136,7 @@ private[internal] trait GlbLubs { mergePrefixAndArgs(ts1, Covariant, depth) match { case NoType => loop(pretypes, tails) case tp if strictInference && willViolateRecursiveBounds(tp, ts0, ts1) => - log(s"Breaking recursion in lublist, advancing frontier and discaring merged prefix/args from $tp") + log(s"Breaking recursion in lublist, advancing frontier and discarding merged prefix/args from $tp") loop(pretypes, tails) case tp => loop(tp :: pretypes, tails) diff --git a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala index cf274f24bb..990092b749 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala @@ -404,7 +404,7 @@ trait TypeComparers { sym2.isClass && { val base = tr1 baseType sym2 // During bootstrap, `base eq NoType` occurs about 2.5 times as often as `base ne NoType`. - // The extra check seems like a worthwhile optimization (about 2.5M useless calls to isSubtype saved during that run). + // The extra check seems like a worthwhile optimization (about 2.5M useless calls to isSubType saved during that run). (base ne tr1) && (base ne NoType) && isSubType(base, tr2, depth) } || diff --git a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala index e321a07f51..2697824fd5 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala @@ -25,7 +25,7 @@ private[internal] trait TypeConstraints { // register with the auto-clearing cache manager perRunCaches.recordCache(this) - /** Undo all changes to constraints to type variables upto `limit`. */ + /** Undo all changes to constraints to type variables up to `limit`. */ //OPT this method is public so we can do `manual inlining` def undoTo(limit: UndoPairs) { assertCorrectThread() diff --git a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala index de065d0b5d..0601067d26 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala @@ -312,7 +312,7 @@ private[internal] trait TypeMaps { * the corresponding class file might still not be read, so we do not * know what the type parameters of the type are. Therefore * the conversion of raw types to existential types might not have taken place - * in ClassFileparser.sigToType (where it is usually done). + * in ClassFileParser.sigToType (where it is usually done). */ def rawToExistential = new TypeMap { private var expanded = immutable.Set[Symbol]() @@ -404,7 +404,7 @@ private[internal] trait TypeMaps { case _ => super.mapOver(tp) } - // Do not discard the types of existential ident's. The + // Do not discard the types of existential idents. The // symbol of the Ident itself cannot be listed in the // existential's parameters, so the resulting existential // type would be ill-formed. @@ -504,7 +504,7 @@ private[internal] trait TypeMaps { && isBaseClassOfEnclosingClass(sym.owner) ) - private var capturedThisIds= 0 + private var capturedThisIds = 0 private def nextCapturedThisId() = { capturedThisIds += 1; capturedThisIds } /** Creates an existential representing a type parameter which appears * in the prefix of a ThisType. diff --git a/src/reflect/scala/reflect/internal/transform/Erasure.scala b/src/reflect/scala/reflect/internal/transform/Erasure.scala index e2f1e74740..07ae71538c 100644 --- a/src/reflect/scala/reflect/internal/transform/Erasure.scala +++ b/src/reflect/scala/reflect/internal/transform/Erasure.scala @@ -19,7 +19,7 @@ trait Erasure { /* A Java Array<T> is erased to Array[Object] (T can only be a reference type), where as a Scala Array[T] is * erased to Object. However, there is only symbol for the Array class. So to make the distinction between * a Java and a Scala array, we check if the owner of T comes from a Java class. - * This however caused issue SI-5654. The additional test for EXSITENTIAL fixes it, see the ticket comments. + * This however caused issue SI-5654. The additional test for EXISTENTIAL fixes it, see the ticket comments. * In short, members of an existential type (e.g. `T` in `forSome { type T }`) can have pretty arbitrary * owners (e.g. when computing lubs, <root> is used). All packageClass symbols have `isJavaDefined == true`. */ @@ -161,6 +161,11 @@ trait Erasure { } if (newParents eq parents) tp else ClassInfoType(newParents, decls, clazz) + + // can happen while this map is being used before erasure (e.g. when reasoning about sam types) + // the regular mapOver will cause a class cast exception because TypeBounds don't erase to TypeBounds + case _: BoundedWildcardType => tp // skip + case _ => mapOver(tp) } diff --git a/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala b/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala index 3cede1b3c5..49ab0cb30e 100644 --- a/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala +++ b/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala @@ -92,7 +92,7 @@ class AbstractFileClassLoader(val root: AbstractFile, parent: ClassLoader) } } - private val packages = mutable.Map[String, Package]() + private[this] val packages = mutable.Map[String, Package]() override def definePackage(name: String, specTitle: String, specVersion: String, specVendor: String, implTitle: String, implVersion: String, implVendor: String, sealBase: URL): Package = { throw new UnsupportedOperationException() diff --git a/src/reflect/scala/reflect/internal/util/Statistics.scala b/src/reflect/scala/reflect/internal/util/Statistics.scala index 905f1bf26e..2d623f3367 100644 --- a/src/reflect/scala/reflect/internal/util/Statistics.scala +++ b/src/reflect/scala/reflect/internal/util/Statistics.scala @@ -78,7 +78,7 @@ object Statistics { /** Create a new stackable that shows as `prefix` and is active * in the same phases as its base timer. Stackable timers are subtimers - * that can be stacked ina timerstack, and that print aggregate, as well as specific + * that can be stacked in a timerstack, and that print aggregate, as well as specific * durations. */ def newStackableTimer(prefix: String, timer: Timer): StackableTimer = new StackableTimer(prefix, timer) diff --git a/src/reflect/scala/reflect/internal/util/StringOps.scala b/src/reflect/scala/reflect/internal/util/StringOps.scala index 79195e6eab..2fee6b0f82 100644 --- a/src/reflect/scala/reflect/internal/util/StringOps.scala +++ b/src/reflect/scala/reflect/internal/util/StringOps.scala @@ -11,7 +11,7 @@ package reflect package internal package util -import scala.compat.Platform.EOL +import java.lang.System.{lineSeparator => EOL} /** This object provides utility methods to extract elements * from Strings. @@ -45,7 +45,7 @@ trait StringOps { else s.substring(0, end) } /** Breaks the string into lines and strips each line before reassembling. */ - def trimAllTrailingSpace(s: String): String = s.lines map trimTrailingSpace mkString EOL + def trimAllTrailingSpace(s: String): String = s.lines.map(trimTrailingSpace).mkString(EOL) def decompose(str: String, sep: Char): List[String] = { def ws(start: Int): List[String] = @@ -69,18 +69,17 @@ trait StringOps { else Some((str take idx, str drop (if (doDropIndex) idx + 1 else idx))) /** Returns a string meaning "n elements". + * Don't try an element such as "index" with irregular plural. */ - def countElementsAsString(n: Int, elements: String): String = + def countElementsAsString(n: Int, element: String): String = n match { - case 0 => s"no ${elements}s" - case 1 => "one " + elements - case 2 => "two " + elements + "s" - case 3 => "three " + elements + "s" - case 4 => "four " + elements + "s" - case _ => s"$n ${elements}s" + case 0 => s"no ${element}s" + case 1 => s"one ${element}" + case _ => s"${countAsString(n)} ${element}s" } /** Turns a count into a friendly English description if n<=4. + * Otherwise, a scary math representation. */ def countAsString(n: Int): String = n match { @@ -89,8 +88,8 @@ trait StringOps { case 2 => "two" case 3 => "three" case 4 => "four" - case _ => "" + n + case _ => n.toString } } -object StringOps extends StringOps { } +object StringOps extends StringOps diff --git a/src/reflect/scala/reflect/io/Path.scala b/src/reflect/scala/reflect/io/Path.scala index 5f93506015..c5b5ae24ba 100644 --- a/src/reflect/scala/reflect/io/Path.scala +++ b/src/reflect/scala/reflect/io/Path.scala @@ -107,19 +107,20 @@ class Path private[io] (val jfile: JFile) { def /(child: Directory): Directory = /(child: Path).toDirectory def /(child: File): File = /(child: Path).toFile - /** If this path is a container, recursively iterate over its contents. + /** If this path is a directory, recursively iterate over its contents. * The supplied condition is a filter which is applied to each element, - * with that branch of the tree being closed off if it is true. So for - * example if the condition is true for some subdirectory, nothing - * under that directory will be in the Iterator; but otherwise each - * file and subdirectory underneath it will appear. + * with that branch of the tree being closed off if it is false. + * So for example if the condition is false for some subdirectory, nothing + * under that directory will be in the Iterator. If it's true, all files for + * which the condition holds and are directly in that subdirectory are in the + * Iterator, and all sub-subdirectories are recursively evaluated */ def walkFilter(cond: Path => Boolean): Iterator[Path] = if (isFile) toFile walkFilter cond else if (isDirectory) toDirectory walkFilter cond else Iterator.empty - /** Equivalent to walkFilter(_ => false). + /** Equivalent to walkFilter(_ => true). */ def walk: Iterator[Path] = walkFilter(_ => true) diff --git a/src/reflect/scala/reflect/macros/blackbox/Context.scala b/src/reflect/scala/reflect/macros/blackbox/Context.scala index ce28b5911e..205e3ad1c3 100644 --- a/src/reflect/scala/reflect/macros/blackbox/Context.scala +++ b/src/reflect/scala/reflect/macros/blackbox/Context.scala @@ -26,7 +26,7 @@ package blackbox * Refer to the documentation of top-level traits in this package to learn the details. * * If a macro def refers to a macro impl that uses `blackbox.Context`, then this macro def becomes a blackbox macro, - * which means that its expansion will be upcast to its return type, enforcing faithfullness of that macro to its + * which means that its expansion will be upcast to its return type, enforcing faithfulness of that macro to its * type signature. Whitebox macros, i.e. the ones defined with `whitebox.Context`, aren't bound by this restriction, * which enables a number of important use cases, but they are also going to enjoy less support than blackbox macros, * so choose wisely. See the [[http://docs.scala-lang.org/overviews/macros/overview.html Macros Guide]] for more information. diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala index 95d6662d14..72e21f67fe 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala @@ -429,6 +429,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => definitions.hijackedCoreClasses definitions.symbolsNotPresentInBytecode definitions.isPossibleSyntheticParent + definitions.ShowAsInfixAnnotationClass definitions.abbrvTag definitions.numericWeight definitions.boxedModule @@ -458,8 +459,8 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => definitions.DoubleTpe definitions.BooleanTpe definitions.ScalaNumericValueClasses - definitions.ScalaValueClassesNoUnit definitions.ScalaValueClasses + definitions.ScalaValueClassesNoUnit uncurry.VarargsSymbolAttachment uncurry.DesugaredParameterType diff --git a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala index f0d96e0fd6..eadafc8abb 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala @@ -18,6 +18,12 @@ private[reflect] trait SynchronizedOps extends internal.SymbolTable if (elems.exists(_.isInstanceOf[RefinedType])) new BaseTypeSeq(parents, elems) with SynchronizedBaseTypeSeq else new BaseTypeSeq(parents, elems) + override protected def newMappedBaseTypeSeq(orig: BaseTypeSeq, f: Type => Type) = + // MappedBaseTypeSeq's are used rarely enough that we unconditionally mixin the synchronized + // wrapper, rather than doing this conditionally. A previous attempt to do that broke the "late" + // part of the "lateMap" contract in inspecting the mapped elements. + new MappedBaseTypeSeq(orig, f) with SynchronizedBaseTypeSeq + trait SynchronizedBaseTypeSeq extends BaseTypeSeq { override def apply(i: Int): Type = gilSynchronized { super.apply(i) } override def rawElem(i: Int) = gilSynchronized { super.rawElem(i) } @@ -28,11 +34,6 @@ private[reflect] trait SynchronizedOps extends internal.SymbolTable override def exists(p: Type => Boolean): Boolean = gilSynchronized { super.exists(p) } override lazy val maxDepth = gilSynchronized { maxDepthOfElems } override def toString = gilSynchronized { super.toString } - - override def lateMap(f: Type => Type): BaseTypeSeq = - // only need to synchronize BaseTypeSeqs if they contain refined types - if (map(f).toList.exists(_.isInstanceOf[RefinedType])) new MappedBaseTypeSeq(this, f) with SynchronizedBaseTypeSeq - else new MappedBaseTypeSeq(this, f) } // Scopes diff --git a/src/repl/scala/tools/nsc/interpreter/ExprTyper.scala b/src/repl/scala/tools/nsc/interpreter/ExprTyper.scala index 01e3a90950..f68705211f 100644 --- a/src/repl/scala/tools/nsc/interpreter/ExprTyper.scala +++ b/src/repl/scala/tools/nsc/interpreter/ExprTyper.scala @@ -13,6 +13,12 @@ trait ExprTyper { import global.{ reporter => _, Import => _, _ } import naming.freshInternalVarName + private def doInterpret(code: String): IR.Result = { + // interpret/interpretSynthetic may change the phase, which would have unintended effects on types. + val savedPhase = phase + try interpretSynthetic(code) finally phase = savedPhase + } + def symbolOfLine(code: String): Symbol = { def asExpr(): Symbol = { val name = freshInternalVarName() @@ -21,7 +27,7 @@ trait ExprTyper { // behind a def and strip the NullaryMethodType which wraps the expr. val line = "def " + name + " = " + code - interpretSynthetic(line) match { + doInterpret(line) match { case IR.Success => val sym0 = symbolOfTerm(name) // drop NullaryMethodType @@ -32,7 +38,7 @@ trait ExprTyper { def asDefn(): Symbol = { val old = repl.definedSymbolList.toSet - interpretSynthetic(code) match { + doInterpret(code) match { case IR.Success => repl.definedSymbolList filterNot old match { case Nil => NoSymbol @@ -43,7 +49,7 @@ trait ExprTyper { } } def asError(): Symbol = { - interpretSynthetic(code) + doInterpret(code) NoSymbol } beSilentDuring(asExpr()) orElse beSilentDuring(asDefn()) orElse asError() @@ -72,7 +78,7 @@ trait ExprTyper { def asProperType(): Option[Type] = { val name = freshInternalVarName() val line = "def %s: %s = ???" format (name, typeString) - interpretSynthetic(line) match { + doInterpret(line) match { case IR.Success => val sym0 = symbolOfTerm(name) Some(sym0.asMethod.returnType) diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala index d1096fda4e..9635f320fe 100644 --- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala @@ -9,6 +9,7 @@ package interpreter import scala.language.{ implicitConversions, existentials } import scala.annotation.tailrec import Predef.{ println => _, _ } +import PartialFunction.{cond => when} import interpreter.session._ import StdReplTags._ import scala.tools.asm.ClassReader @@ -17,7 +18,7 @@ import scala.tools.nsc.util.{ ClassPath, stringFromStream } import scala.reflect.classTag import scala.reflect.internal.util.{ BatchSourceFile, ScalaClassLoader, NoPosition } import ScalaClassLoader._ -import scala.reflect.io.File +import scala.reflect.io.{Directory, File, Path} import scala.tools.util._ import io.AbstractFile import scala.concurrent.{ ExecutionContext, Await, Future } @@ -26,6 +27,8 @@ import java.io.BufferedReader import scala.util.{ Try, Success, Failure } +import Completion._ + /** The Scala interactive shell. It provides a read-eval-print loop * around the Interpreter class. * After instantiation, clients should call the main() method. @@ -119,37 +122,6 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) intp = new ILoopInterpreter } - /** print a friendly help message */ - def helpCommand(line: String): Result = line match { - case "" => helpSummary() - case CommandMatch(cmd) => echo(f"%n${cmd.help}") - case _ => ambiguousError(line) - } - private def helpSummary() = { - val usageWidth = commands map (_.usageMsg.length) max - val formatStr = s"%-${usageWidth}s %s" - - echo("All commands can be abbreviated, e.g., :he instead of :help.") - - for (cmd <- commands) echo(formatStr.format(cmd.usageMsg, cmd.help)) - } - private def ambiguousError(cmd: String): Result = { - matchingCommands(cmd) match { - case Nil => echo(cmd + ": no such command. Type :help for help.") - case xs => echo(cmd + " is ambiguous: did you mean " + xs.map(":" + _.name).mkString(" or ") + "?") - } - Result(keepRunning = true, None) - } - // this lets us add commands willy-nilly and only requires enough command to disambiguate - private def matchingCommands(cmd: String) = commands filter (_.name startsWith cmd) - private object CommandMatch { - def unapply(name: String): Option[LoopCommand] = - matchingCommands(name) match { - case x :: Nil => Some(x) - case xs => xs find (_.name == name) // accept an exact match - } - } - /** Show the history */ lazy val historyCommand = new LoopCommand("history", "show the history (optional num is commands to show)") { override def usage = "[num]" @@ -214,16 +186,16 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) cmd("implicits", "[-v]", "show the implicits in scope", intp.implicitsCommand), cmd("javap", "<path|class>", "disassemble a file or class name", javapCommand), cmd("line", "<id>|<line>", "place line(s) at the end of history", lineCommand), - cmd("load", "<path>", "interpret lines in a file", loadCommand), - cmd("paste", "[-raw] [path]", "enter paste mode or paste a file", pasteCommand), + cmd("load", "<path>", "interpret lines in a file", loadCommand, fileCompletion), + cmd("paste", "[-raw] [path]", "enter paste mode or paste a file", pasteCommand, fileCompletion), nullary("power", "enable power user mode", powerCmd), nullary("quit", "exit the interpreter", () => Result(keepRunning = false, None)), - cmd("replay", "[options]", "reset the repl and replay all previous commands", replayCommand), + cmd("replay", "[options]", "reset the repl and replay all previous commands", replayCommand, settingsCompletion), cmd("require", "<path>", "add a jar to the classpath", require), - cmd("reset", "[options]", "reset the repl to its initial state, forgetting all session entries", resetCommand), - cmd("save", "<path>", "save replayable session to a file", saveCommand), + cmd("reset", "[options]", "reset the repl to its initial state, forgetting all session entries", resetCommand, settingsCompletion), + cmd("save", "<path>", "save replayable session to a file", saveCommand, fileCompletion), shCommand, - cmd("settings", "<options>", "update compiler options, if possible; see reset", changeSettings), + cmd("settings", "<options>", "update compiler options, if possible; see reset", changeSettings, settingsCompletion), nullary("silent", "disable/enable automatic printing of results", verbosity), cmd("type", "[-v] <expr>", "display the type of an expression without evaluating it", typeCommand), cmd("kind", "[-v] <expr>", "display the kind of expression's type", kindCommand), @@ -235,6 +207,46 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) cmd("phase", "<phase>", "set the implicit phase for power commands", phaseCommand) ) + // complete filename + val fileCompletion: Completion = new Completion { + def resetVerbosity(): Unit = () + val emptyWord = """(\s+)$""".r.unanchored + val directorily = """(\S*/)$""".r.unanchored + val trailingWord = """(\S+)$""".r.unanchored + def listed(i: Int, dir: Option[Path]) = + dir.filter(_.isDirectory).map(d => Candidates(i, d.toDirectory.list.map(_.name).toList)).getOrElse(NoCandidates) + def listedIn(dir: Directory, name: String) = dir.list.filter(_.name.startsWith(name)).map(_.name).toList + def complete(buffer: String, cursor: Int): Candidates = + buffer.substring(0, cursor) match { + case emptyWord(s) => listed(cursor, Directory.Current) + case directorily(s) => listed(cursor, Option(Path(s))) + case trailingWord(s) => + val f = File(s) + val (i, maybes) = + if (f.isFile) (cursor - s.length, List(f.toAbsolute.path)) + else if (f.isDirectory) (cursor - s.length, List(s"${f.toAbsolute.path}/")) + else if (f.parent.exists) (cursor - f.name.length, listedIn(f.parent.toDirectory, f.name)) + else (-1, Nil) + if (maybes.isEmpty) NoCandidates else Candidates(i, maybes) + case _ => NoCandidates + } + } + + // complete settings name + val settingsCompletion: Completion = new Completion { + def resetVerbosity(): Unit = () + val trailingWord = """(\S+)$""".r.unanchored + def complete(buffer: String, cursor: Int): Candidates = { + buffer.substring(0, cursor) match { + case trailingWord(s) => + val maybes = settings.visibleSettings.filter(_.name.startsWith(s)).map(_.name) + .filterNot(when(_) { case "-"|"-X"|"-Y" => true }).toList.sorted + if (maybes.isEmpty) NoCandidates else Candidates(cursor - s.length, maybes) + case _ => NoCandidates + } + } + } + private def importsCommand(line: String): Result = { val tokens = words(line) val handlers = intp.languageWildcardHandlers ++ intp.importHandlers @@ -681,20 +693,11 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) * (1) whether to keep running, (2) the line to record for replay, if any. */ def command(line: String): Result = { - if (line startsWith ":") colonCommand(line.tail) + if (line startsWith ":") colonCommand(line) else if (intp.global == null) Result(keepRunning = false, None) // Notice failure to create compiler else Result(keepRunning = true, interpretStartingWith(line)) } - private val commandish = """(\S+)(?:\s+)?(.*)""".r - - private def colonCommand(line: String): Result = line.trim match { - case "" => helpSummary() - case commandish(CommandMatch(cmd), rest) => cmd(rest) - case commandish(name, _) => ambiguousError(name) - case _ => echo("?") - } - private def readWhile(cond: String => Boolean) = { Iterator continually in.readLine("") takeWhile (x => x != null && cond(x)) } @@ -849,6 +852,18 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) } } + // delegate to command completion or presentation compiler + class ReplCompletion(intp: IMain) extends Completion { + val pc = new PresentationCompilerCompleter(intp) + def resetVerbosity(): Unit = pc.resetVerbosity() + def complete(buffer: String, cursor: Int): Completion.Candidates = { + if (buffer.startsWith(":")) + colonCompletion(buffer, cursor).complete(buffer, cursor) + else + pc.complete(buffer, cursor) + } + } + /** Tries to create a jline.InteractiveReader, falling back to SimpleReader, * unless settings or properties are such that it should start with SimpleReader. * The constructor of the InteractiveReader must take a Completion strategy, @@ -868,7 +883,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) } def mkReader(maker: ReaderMaker) = maker { () => - if (settings.noCompletion) NoCompletion else new PresentationCompilerCompleter(intp) + if (settings.noCompletion) NoCompletion else new ReplCompletion(intp) } def internalClass(kind: String) = s"scala.tools.nsc.interpreter.$kind.InteractiveReader" @@ -1014,6 +1029,7 @@ object ILoop { // like if you'd just typed it into the repl. def runForTranscript(code: String, settings: Settings, inSession: Boolean = false): String = { import java.io.{ BufferedReader, StringReader, OutputStreamWriter } + import java.lang.System.{lineSeparator => EOL} stringFromStream { ostream => Console.withOut(ostream) { @@ -1021,10 +1037,9 @@ object ILoop { // skip margin prefix for continuation lines, unless preserving session text for test // should test for repl.paste.ContinueString or replProps.continueText.contains(ch) override def write(str: String) = - if (!inSession && (str forall (ch => ch.isWhitespace || ch == '|'))) () - else super.write(str) + if (inSession || (str.exists(ch => ch != ' ' && ch != '|'))) super.write(str) } - val input = new BufferedReader(new StringReader(code.trim + "\n")) { + val input = new BufferedReader(new StringReader(s"${code.trim}${EOL}")) { override def readLine(): String = { mark(1) // default buffer is 8k val c = read() diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index 980d12f9b8..a351d2da95 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -1105,7 +1105,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends def apply(line: String): Result = debugging(s"""parse("$line")""") { var isIncomplete = false - def parse = { + def parse = withoutWarnings { reporter.reset() val trees = newUnitParser(line, label).parseStats() if (reporter.hasErrors) Error(trees) diff --git a/src/repl/scala/tools/nsc/interpreter/LoopCommands.scala b/src/repl/scala/tools/nsc/interpreter/LoopCommands.scala index 8c3b174513..a2ce63996b 100644 --- a/src/repl/scala/tools/nsc/interpreter/LoopCommands.scala +++ b/src/repl/scala/tools/nsc/interpreter/LoopCommands.scala @@ -24,18 +24,21 @@ class ProcessResult(val line: String) { override def toString = "`%s` (%d lines, exit %d)".format(line, buffer.size, exitCode) } -trait LoopCommands { +trait LoopCommands { self: { def echo(msg: String): Unit } => protected def out: JPrintWriter // So outputs can be suppressed. - def echoCommandMessage(msg: String): Unit = out println msg + def echoCommandMessage(msg: String): Unit = out.println(msg) + + // available commands + def commands: List[LoopCommand] // a single interpreter command abstract class LoopCommand(val name: String, val help: String) extends (String => Result) { def usage: String = "" - def usageMsg: String = ":" + name + ( + def usageMsg: String = s":$name${ if (usage == "") "" else " " + usage - ) + }" def apply(line: String): Result // called if no args are given @@ -43,21 +46,88 @@ trait LoopCommands { "usage is " + usageMsg Result(keepRunning = true, None) } + + // subclasses may provide completions + def completion: Completion = NoCompletion } object LoopCommand { def nullary(name: String, help: String, f: () => Result): LoopCommand = new NullaryCmd(name, help, _ => f()) - def cmd(name: String, usage: String, help: String, f: String => Result): LoopCommand = + def cmd(name: String, usage: String, help: String, f: String => Result, completion: Completion = NoCompletion): LoopCommand = if (usage == "") new NullaryCmd(name, help, f) - else new LineCmd(name, usage, help, f) + else new LineCmd(name, usage, help, f, completion) + } + + /** print a friendly help message */ + def helpCommand(line: String): Result = line match { + case "" => helpSummary() + case CommandMatch(cmd) => echo(f"%n${cmd.help}") + case _ => ambiguousError(line) + } + + def helpSummary() = { + val usageWidth = commands map (_.usageMsg.length) max + val formatStr = s"%-${usageWidth}s %s" + + echo("All commands can be abbreviated, e.g., :he instead of :help.") + + for (cmd <- commands) echo(formatStr.format(cmd.usageMsg, cmd.help)) + } + def ambiguousError(cmd: String): Result = { + matchingCommands(cmd) match { + case Nil => echo(cmd + ": no such command. Type :help for help.") + case xs => echo(cmd + " is ambiguous: did you mean " + xs.map(":" + _.name).mkString(" or ") + "?") + } + Result(keepRunning = true, None) + } + + // all commands with given prefix + private def matchingCommands(cmd: String) = commands.filter(_.name.startsWith(cmd.stripPrefix(":"))) + + // extract command from partial name, or prefer exact match if multiple matches + private object CommandMatch { + def unapply(name: String): Option[LoopCommand] = + matchingCommands(name) match { + case Nil => None + case x :: Nil => Some(x) + case xs => xs find (_.name == name) + } + } + + // extract command name and rest of line + private val commandish = """(\S+)(?:\s+)?(.*)""".r + + def colonCommand(line: String): Result = line.trim match { + case "" => helpSummary() + case commandish(CommandMatch(cmd), rest) => cmd(rest) + case commandish(name, _) => ambiguousError(name) + case _ => echo("?") + } + + import Completion.Candidates + + def colonCompletion(line: String, cursor: Int): Completion = line.trim match { + case commandish(name @ CommandMatch(cmd), rest) => + if (name.length > cmd.name.length) cmd.completion + else + new Completion { + def resetVerbosity(): Unit = () + def complete(buffer: String, cursor: Int) = Candidates(cursor - name.length + 1, List(cmd.name)) + } + case commandish(name, _) if matchingCommands(name).nonEmpty => + new Completion { + def resetVerbosity(): Unit = () + def complete(buffer: String, cursor: Int) = Candidates(cursor - name.length + 1, matchingCommands(name).map(_.name)) + } + case _ => NoCompletion } class NullaryCmd(name: String, help: String, f: String => Result) extends LoopCommand(name, help) { def apply(line: String): Result = f(line) } - class LineCmd(name: String, argWord: String, help: String, f: String => Result) extends LoopCommand(name, help) { + class LineCmd(name: String, argWord: String, help: String, f: String => Result, override val completion: Completion) extends LoopCommand(name, help) { override def usage = argWord def apply(line: String): Result = f(line) } diff --git a/src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala b/src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala index d6c0dafaf2..f455e71476 100644 --- a/src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala +++ b/src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala @@ -213,29 +213,40 @@ trait MemberHandlers { class ImportHandler(imp: Import) extends MemberHandler(imp) { val Import(expr, selectors) = imp + def targetType = intp.global.rootMirror.getModuleIfDefined("" + expr) match { case NoSymbol => intp.typeOfExpression("" + expr) - case sym => sym.thisType + case sym => sym.tpe } - private def importableTargetMembers = importableMembers(targetType).toList - // wildcard imports, e.g. import foo._ - private def selectorWild = selectors filter (_.name == nme.USCOREkw) - // renamed imports, e.g. import foo.{ bar => baz } - private def selectorRenames = selectors map (_.rename) filterNot (_ == null) + + private def isFlattenedSymbol(sym: Symbol) = + sym.owner.isPackageClass && + sym.name.containsName(nme.NAME_JOIN_STRING) && + sym.owner.info.member(sym.name.take(sym.name.indexOf(nme.NAME_JOIN_STRING))) != NoSymbol + + private def importableTargetMembers = + importableMembers(exitingTyper(targetType)).filterNot(isFlattenedSymbol).toList + + // non-wildcard imports + private def individualSelectors = selectors filter analyzer.isIndividualImport /** Whether this import includes a wildcard import */ - val importsWildcard = selectorWild.nonEmpty + val importsWildcard = selectors exists analyzer.isWildcardImport def implicitSymbols = importedSymbols filter (_.isImplicit) def importedSymbols = individualSymbols ++ wildcardSymbols - private val selectorNames = selectorRenames filterNot (_ == nme.USCOREkw) flatMap (_.bothNames) toSet - lazy val individualSymbols: List[Symbol] = exitingTyper(importableTargetMembers filter (m => selectorNames(m.name))) - lazy val wildcardSymbols: List[Symbol] = exitingTyper(if (importsWildcard) importableTargetMembers else Nil) + lazy val importableSymbolsWithRenames = { + val selectorRenameMap = individualSelectors.flatMap(x => x.name.bothNames zip x.rename.bothNames).toMap + importableTargetMembers flatMap (m => selectorRenameMap.get(m.name) map (m -> _)) + } + + lazy val individualSymbols: List[Symbol] = importableSymbolsWithRenames map (_._1) + lazy val wildcardSymbols: List[Symbol] = if (importsWildcard) importableTargetMembers else Nil /** Complete list of names imported by a wildcard */ lazy val wildcardNames: List[Name] = wildcardSymbols map (_.name) - lazy val individualNames: List[Name] = individualSymbols map (_.name) + lazy val individualNames: List[Name] = importableSymbolsWithRenames map (_._2) /** The names imported by this statement */ override lazy val importedNames: List[Name] = wildcardNames ++ individualNames diff --git a/src/repl/scala/tools/nsc/interpreter/ReplProps.scala b/src/repl/scala/tools/nsc/interpreter/ReplProps.scala index f3115d9800..a86069f198 100644 --- a/src/repl/scala/tools/nsc/interpreter/ReplProps.scala +++ b/src/repl/scala/tools/nsc/interpreter/ReplProps.scala @@ -17,7 +17,7 @@ class ReplProps { private def int(name: String) = Prop[Int](name) // This property is used in TypeDebugging. Let's recycle it. - val colorOk = bool("scala.color") + val colorOk = Properties.coloredOutputEnabled val info = bool("scala.repl.info") val debug = bool("scala.repl.debug") diff --git a/src/repl/scala/tools/nsc/interpreter/Scripted.scala b/src/repl/scala/tools/nsc/interpreter/Scripted.scala index 6aef486957..8d87d98e53 100644 --- a/src/repl/scala/tools/nsc/interpreter/Scripted.scala +++ b/src/repl/scala/tools/nsc/interpreter/Scripted.scala @@ -331,7 +331,7 @@ class WriterOutputStream(writer: Writer) extends OutputStream { byteBuffer.flip() val result = decoder.decode(byteBuffer, charBuffer, /*eoi=*/ false) if (byteBuffer.remaining == 0) byteBuffer.clear() - if (charBuffer.position > 0) { + if (charBuffer.position() > 0) { charBuffer.flip() writer write charBuffer.toString charBuffer.clear() diff --git a/src/scaladoc/scala/tools/nsc/doc/base/comment/Body.scala b/src/scaladoc/scala/tools/nsc/doc/base/comment/Body.scala index 0560833618..2524fb75fb 100644 --- a/src/scaladoc/scala/tools/nsc/doc/base/comment/Body.scala +++ b/src/scaladoc/scala/tools/nsc/doc/base/comment/Body.scala @@ -11,8 +11,9 @@ package comment import scala.collection._ /** A body of text. A comment has a single body, which is composed of - * at least one block. Inside every body is exactly one summary (see - * [[scala.tools.nsc.doc.model.comment.Summary]]). */ + * at least one block. Inside every body is exactly one summary. + * @see [[Summary]] + */ final case class Body(blocks: Seq[Block]) { /** The summary text of the comment body. */ diff --git a/src/scaladoc/scala/tools/nsc/doc/base/comment/Comment.scala b/src/scaladoc/scala/tools/nsc/doc/base/comment/Comment.scala index 5d0b6782bc..55527e43a1 100644 --- a/src/scaladoc/scala/tools/nsc/doc/base/comment/Comment.scala +++ b/src/scaladoc/scala/tools/nsc/doc/base/comment/Comment.scala @@ -12,7 +12,7 @@ import scala.collection._ /** A Scaladoc comment and all its tags. * - * '''Note:''' the only instantiation site of this class is in [[CommentFactory]]. + * '''Note:''' the only instantiation site of this class is in [[model.CommentFactory]]. * * @author Manohar Jonnalagedda * @author Gilles Dubochet */ diff --git a/test/benchmarks/src/main/scala/scala/collection/immutable/HashMapBenchmark.scala b/test/benchmarks/src/main/scala/scala/collection/immutable/HashMapBenchmark.scala new file mode 100644 index 0000000000..134cd6879b --- /dev/null +++ b/test/benchmarks/src/main/scala/scala/collection/immutable/HashMapBenchmark.scala @@ -0,0 +1,56 @@ +package scala.collection.immutable + +import org.openjdk.jmh.annotations._ +import org.openjdk.jmh.infra._ +import org.openjdk.jmh.runner.IterationType +import benchmark._ +import java.util.concurrent.TimeUnit + +@BenchmarkMode(Array(Mode.AverageTime)) +@Fork(2) +@Threads(1) +@Warmup(iterations = 10) +@Measurement(iterations = 10) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Benchmark) +class HashMapBenchmark { + @Param(Array("10", "100", "1000")) + var size: Int = _ + + var existingKeys: Array[Any] = _ + var missingKeys: Array[Any] = _ + + @Setup(Level.Trial) def initKeys(): Unit = { + existingKeys = (0 to size).map(i => (i % 4) match { + case 0 => i.toString + case 1 => i.toChar + case 2 => i.toDouble + case 3 => i.toInt + }).toArray + missingKeys = (size to 2 * size).toArray + } + + var map: collection.immutable.HashMap[Any, Any] = null + + @Setup(Level.Trial) def initialize = { + map = collection.immutable.HashMap(existingKeys.map(x => (x, x)) : _*) + } + + @Benchmark def contains(bh: Blackhole): Unit = { + var i = 0; + while (i < size) { + bh.consume(map.contains(existingKeys(i))) + bh.consume(map.contains(missingKeys(i))) + i += 1 + } + } + + @Benchmark def get(bh: Blackhole): Unit = { + var i = 0; + while (i < size) { + bh.consume(map.get(existingKeys(i))) + bh.consume(map.get(missingKeys(i))) + i += 1 + } + } +} diff --git a/test/benchmarks/src/main/scala/scala/collection/immutable/ListBenchmark.scala b/test/benchmarks/src/main/scala/scala/collection/immutable/ListBenchmark.scala new file mode 100644 index 0000000000..94844dcae2 --- /dev/null +++ b/test/benchmarks/src/main/scala/scala/collection/immutable/ListBenchmark.scala @@ -0,0 +1,72 @@ +package scala.collection.immutable + +import java.util.concurrent.TimeUnit + +import org.openjdk.jmh.annotations._ + +object ListBenchmark { + case class Content(value: Int) +} + +@BenchmarkMode(Array(Mode.AverageTime)) +@Fork(2) +@Threads(1) +@Warmup(iterations = 10) +@Measurement(iterations = 10) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Benchmark) +class ListBenchmark { + import ListBenchmark._ + @Param(Array("0", "1", "10", "100", "1000")) + var size: Int = _ + + var values: List[Content] = _ + var mid: Content = _ + var last: Content = _ + + + @Setup(Level.Trial) def initKeys(): Unit = { + values = List.tabulate(size)(v => Content(v)) + mid = Content(size / 2) + last = Content(Math.max(0,size -1)) + } + + @Benchmark def filter_includeAll: Any = { + values.filter(v => true) + } + + @Benchmark def filter_excludeAll: Any = { + values.filter(_ => false) + } + + @Benchmark def filter_exc_mid: Any = { + values.filter(v => v.value != mid.value) + } + + @Benchmark def filter_from_mid: Any = { + values.filter(v => v.value <= mid.value) + } + + @Benchmark def filter_exc_last: Any = { + values.filter(v => v.value != last.value) + } + + @Benchmark def filter_only_last: Any = { + values.filter(v => v.value == last.value) + } + + @Setup(Level.Trial) def initKeys(): Unit = { + values = List.tabulate(size)(n => if (n == size / 2) "mid" else "") + } + + @Benchmark def mapConserve_identity: Any = { + values.mapConserve(x => x) + } + + @Benchmark def mapConserve_modifyAll: Any = { + values.mapConserve(x => "replace") + } + @Benchmark def mapConserve_modifyMid: Any = { + values.mapConserve(x => if (x == "mid") "replace" else x) + } +} diff --git a/test/files/neg/literals.check b/test/files/neg/literals.check index 148a9346c5..79b6d47782 100644 --- a/test/files/neg/literals.check +++ b/test/files/neg/literals.check @@ -19,6 +19,18 @@ literals.scala:23: error: missing integer number literals.scala:27: error: Decimal integer literals may not have a leading zero. (Octal syntax is obsolete.) def tooManyZeros: Int = 00 // line 26: no leading zero ^ +literals.scala:40: error: floating point number too small + def tooTiny: Float = { 0.7e-45f } // floating point number too small + ^ +literals.scala:42: error: double precision floating point number too small + def twoTiny: Double = { 2.0e-324 } // double precision floating point number too small + ^ +literals.scala:44: error: floating point number too large + def tooHuge: Float = { 3.4028236E38f } // floating point number too large + ^ +literals.scala:46: error: double precision floating point number too large + def twoHuge: Double = { 1.7976931348623159e308 } // double precision floating point number too large + ^ literals.scala:14: error: identifier expected but '}' found. def orphanDot: Int = { 9. } // line 12: ident expected ^ @@ -37,4 +49,4 @@ literals.scala:29: error: ';' expected but 'def' found. literals.scala:33: error: identifier expected but 'def' found. def zeroOfNineDot: Int = 09. // line 32: malformed integer, ident expected ^ -13 errors found +17 errors found diff --git a/test/files/neg/literals.scala b/test/files/neg/literals.scala index 3df7f0b408..22d5d9acd1 100644 --- a/test/files/neg/literals.scala +++ b/test/files/neg/literals.scala @@ -1,6 +1,6 @@ /* This took me literally all day. -*/ + */ trait RejectedLiterals { def missingHex: Int = { 0x } // line 4: was: not reported, taken as zero @@ -34,3 +34,14 @@ trait Braceless { def noHexFloat: Double = 0x1.2 // line 34: ';' expected but double literal found. } + +trait MoreSadness { + + def tooTiny: Float = { 0.7e-45f } // floating point number too small + + def twoTiny: Double = { 2.0e-324 } // double precision floating point number too small + + def tooHuge: Float = { 3.4028236E38f } // floating point number too large + + def twoHuge: Double = { 1.7976931348623159e308 } // double precision floating point number too large +} diff --git a/test/files/neg/nested-fn-print.check b/test/files/neg/nested-fn-print.check index ea278554d4..feeac0733f 100644 --- a/test/files/neg/nested-fn-print.check +++ b/test/files/neg/nested-fn-print.check @@ -1,4 +1,4 @@ -nested-fn-print.scala:4: error: only classes can have declared but undefined members +nested-fn-print.scala:4: error: only traits and abstract classes can have declared but undefined members (Note that variables need to be initialized to be defined) var x3: Int => Double ^ diff --git a/test/files/neg/quasiquotes-syntax-error-position.check b/test/files/neg/quasiquotes-syntax-error-position.check index 9fd6ce0417..b12a7d13d6 100644 --- a/test/files/neg/quasiquotes-syntax-error-position.check +++ b/test/files/neg/quasiquotes-syntax-error-position.check @@ -16,8 +16,7 @@ quasiquotes-syntax-error-position.scala:9: error: '{' expected but end of quote quasiquotes-syntax-error-position.scala:10: error: ';' expected but '@' found. q"foo@$a" ^ -quasiquotes-syntax-error-position.scala:11: error: case classes without a parameter list are not allowed; -use either case objects or case classes with an explicit `()' as a parameter list. +quasiquotes-syntax-error-position.scala:11: error: case classes must have a parameter list; try 'case class A()' or 'case object A' q"case class A" ^ quasiquotes-syntax-error-position.scala:12: error: identifier expected but ']' found. diff --git a/test/files/neg/t10066.check b/test/files/neg/t10066.check new file mode 100644 index 0000000000..3555205d83 --- /dev/null +++ b/test/files/neg/t10066.check @@ -0,0 +1,7 @@ +t10066.scala:33: error: could not find implicit value for parameter extractor: dynamicrash.Extractor[String] + println(storage.foo[String]) + ^ +t10066.scala:37: error: could not find implicit value for parameter extractor: dynamicrash.Extractor[A] + println(storage.foo) + ^ +two errors found diff --git a/test/files/neg/t10066.scala b/test/files/neg/t10066.scala new file mode 100644 index 0000000000..ef52f333dd --- /dev/null +++ b/test/files/neg/t10066.scala @@ -0,0 +1,38 @@ +package dynamicrash + +import scala.language.dynamics + +class Config + +trait Extractor[A] { + def extract(config: Config, name: String): A +} + +object Extractor { + // note missing "implicit" + val stringExtractor = new Extractor[String] { + override def extract(config: Config, name: String): String = ??? + } +} + +class Workspace extends Dynamic { + val config: Config = new Config + + def selectDynamic[A](name: String)(implicit extractor: Extractor[A]): A = + extractor.extract(config, name) +} + +object Main { + val storage = new Workspace + + // this line works fine + // val a = storage.foo + + // this line crashes the compiler ("head of empty list") + // in ContextErrors$InferencerContextErrors$InferErrorGen$.NotWithinBoundsErrorMessage + println(storage.foo[String]) + + // this line crashes the compiler in different way ("unknown type") + // in the backend, warning: an unexpected type representation reached the compiler backend while compiling Test.scala: <error> + println(storage.foo) +} diff --git a/test/files/neg/t10097.check b/test/files/neg/t10097.check new file mode 100644 index 0000000000..1f70546b57 --- /dev/null +++ b/test/files/neg/t10097.check @@ -0,0 +1,10 @@ +t10097.scala:2: error: case classes must have a non-implicit parameter list; try 'case class C()(...)' +case class C(implicit val c: Int) + ^ +t10097.scala:4: error: case classes must have a non-implicit parameter list; try 'case class D()(...)(...)' +case class D(implicit c: Int)(s: String) + ^ +t10097.scala:4: error: an implicit parameter section must be last +case class D(implicit c: Int)(s: String) + ^ +three errors found diff --git a/test/files/neg/t10097.flags b/test/files/neg/t10097.flags new file mode 100644 index 0000000000..714bbf5125 --- /dev/null +++ b/test/files/neg/t10097.flags @@ -0,0 +1 @@ +-Xsource:2.13 diff --git a/test/files/neg/t10097.scala b/test/files/neg/t10097.scala new file mode 100644 index 0000000000..b2f05e2972 --- /dev/null +++ b/test/files/neg/t10097.scala @@ -0,0 +1,4 @@ + +case class C(implicit val c: Int) + +case class D(implicit c: Int)(s: String) diff --git a/test/files/neg/t10097b.check b/test/files/neg/t10097b.check new file mode 100644 index 0000000000..14535fee34 --- /dev/null +++ b/test/files/neg/t10097b.check @@ -0,0 +1,6 @@ +t10097b.scala:2: warning: case classes should have a non-implicit parameter list; adapting to 'case class C()(...)' +case class C(implicit val c: Int) + ^ +error: No warnings can be incurred under -Xfatal-warnings. +one warning found +one error found diff --git a/test/files/neg/t10097b.flags b/test/files/neg/t10097b.flags new file mode 100644 index 0000000000..c6bfaf1f64 --- /dev/null +++ b/test/files/neg/t10097b.flags @@ -0,0 +1 @@ +-deprecation -Xfatal-warnings diff --git a/test/files/neg/t10097b.scala b/test/files/neg/t10097b.scala new file mode 100644 index 0000000000..f166db6792 --- /dev/null +++ b/test/files/neg/t10097b.scala @@ -0,0 +1,3 @@ + +case class C(implicit val c: Int) + diff --git a/test/files/neg/t565.check b/test/files/neg/t565.check index 136cc94b6f..d7657c0f5d 100644 --- a/test/files/neg/t565.check +++ b/test/files/neg/t565.check @@ -1,4 +1,4 @@ -t565.scala:2: error: only classes can have declared but undefined members +t565.scala:2: error: only traits and abstract classes can have declared but undefined members (Note that variables need to be initialized to be defined) var s0: String ^ diff --git a/test/files/neg/t8217-local-alias-requires-rhs.check b/test/files/neg/t8217-local-alias-requires-rhs.check index d970400ff6..383b1f8d63 100644 --- a/test/files/neg/t8217-local-alias-requires-rhs.check +++ b/test/files/neg/t8217-local-alias-requires-rhs.check @@ -1,10 +1,10 @@ -t8217-local-alias-requires-rhs.scala:3: error: only classes can have declared but undefined members +t8217-local-alias-requires-rhs.scala:3: error: only traits and abstract classes can have declared but undefined members type A ^ -t8217-local-alias-requires-rhs.scala:6: error: only classes can have declared but undefined members +t8217-local-alias-requires-rhs.scala:6: error: only traits and abstract classes can have declared but undefined members type B ^ -t8217-local-alias-requires-rhs.scala:14: error: only classes can have declared but undefined members +t8217-local-alias-requires-rhs.scala:14: error: only traits and abstract classes can have declared but undefined members def this(a: Any) = { this(); type C } ^ three errors found diff --git a/test/files/neg/t8685.check b/test/files/neg/t8685.check index 685fd2e951..a31e2e265a 100644 --- a/test/files/neg/t8685.check +++ b/test/files/neg/t8685.check @@ -4,6 +4,9 @@ case class D @deprecated("ctor D is depr", since="now") (i: Int) t8685.scala:35: warning: class C is deprecated (since now): class C is depr def f = C(42) ^ +t8685.scala:36: warning: constructor D in class D is deprecated (since now): ctor D is depr + def g = D(42) + ^ t8685.scala:37: warning: object E is deprecated (since now): module E is depr def h = E(42) ^ @@ -41,5 +44,5 @@ t8685.scala:53: warning: class K in object J is deprecated (since now): Inner K def l = new J.K(42) ^ error: No warnings can be incurred under -Xfatal-warnings. -14 warnings found +15 warnings found one error found diff --git a/test/files/neg/t8704.check b/test/files/neg/t8704.check new file mode 100644 index 0000000000..b567a8bb17 --- /dev/null +++ b/test/files/neg/t8704.check @@ -0,0 +1,11 @@ +t8704.scala:7: warning: 2 parameter sections are effectively implicit +class D(private implicit val i: Int)(implicit s: String) + ^ +t8704.scala:3: error: an implicit parameter section must be last +class C(i: Int)(implicit j: Int)(implicit k: Int)(n: Int) { + ^ +t8704.scala:3: error: multiple implicit parameter sections are not allowed +class C(i: Int)(implicit j: Int)(implicit k: Int)(n: Int) { + ^ +one warning found +two errors found diff --git a/test/files/neg/t8704.flags b/test/files/neg/t8704.flags new file mode 100644 index 0000000000..f175a06c74 --- /dev/null +++ b/test/files/neg/t8704.flags @@ -0,0 +1 @@ +-Ywarn-extra-implicit diff --git a/test/files/neg/t8704.scala b/test/files/neg/t8704.scala new file mode 100644 index 0000000000..db43bfcaa5 --- /dev/null +++ b/test/files/neg/t8704.scala @@ -0,0 +1,7 @@ + + +class C(i: Int)(implicit j: Int)(implicit k: Int)(n: Int) { + def f = n +} + +class D(private implicit val i: Int)(implicit s: String) diff --git a/test/files/neg/t9636.check b/test/files/neg/t9636.check new file mode 100644 index 0000000000..f36d1d32b2 --- /dev/null +++ b/test/files/neg/t9636.check @@ -0,0 +1,6 @@ +t9636.scala:11: warning: a type was inferred to be `AnyVal`; this may indicate a programming error. + if (signature.sameElements(Array(0x1F, 0x8B))) { + ^ +error: No warnings can be incurred under -Xfatal-warnings. +one warning found +one error found diff --git a/test/files/neg/t9636.flags b/test/files/neg/t9636.flags new file mode 100644 index 0000000000..7949c2afa2 --- /dev/null +++ b/test/files/neg/t9636.flags @@ -0,0 +1 @@ +-Xlint -Xfatal-warnings diff --git a/test/files/neg/t9636.scala b/test/files/neg/t9636.scala new file mode 100644 index 0000000000..7ad5fb3e9e --- /dev/null +++ b/test/files/neg/t9636.scala @@ -0,0 +1,17 @@ + +import java.io._ +import java.util.zip._ + +class C { + def isWrapper(is: FileInputStream): InputStream = { + val pb = new PushbackInputStream(is, 2) + val signature = new Array[Byte](2) + pb.read(signature) + pb.unread(signature) + if (signature.sameElements(Array(0x1F, 0x8B))) { + new GZIPInputStream(new BufferedInputStream(pb)) + } else { + pb + } + } +} diff --git a/test/files/neg/t9675.check b/test/files/neg/t9675.check new file mode 100644 index 0000000000..255477499c --- /dev/null +++ b/test/files/neg/t9675.check @@ -0,0 +1,27 @@ +t9675.scala:4: warning: comparing values of types Test.A and String using `!=' will always yield true + val func1 = (x: A) => { x != "x" } + ^ +t9675.scala:6: warning: comparing values of types Test.A and String using `!=' will always yield true + val func2 = (x: A) => { x != "x" }: Boolean + ^ +t9675.scala:8: warning: comparing values of types Test.A and String using `!=' will always yield true + val func3: Function1[A, Boolean] = (x) => { x != "x" } + ^ +t9675.scala:11: warning: comparing values of types Test.A and String using `!=' will always yield true + def apply(x: A): Boolean = { x != "x" } + ^ +t9675.scala:14: warning: comparing values of types Test.A and String using `!=' will always yield true + def method(x: A): Boolean = { x != "x" } + ^ +t9675.scala:18: warning: comparing values of types Test.A and String using `!=' will always yield true + A("x") != "x" + ^ +t9675.scala:20: warning: comparing values of types Test.A and String using `!=' will always yield true + val func5: Function1[A, Boolean] = (x) => { x != "x" } + ^ +t9675.scala:22: warning: comparing values of types Test.A and String using `!=' will always yield true + List(A("x")).foreach((item: A) => item != "x") + ^ +error: No warnings can be incurred under -Xfatal-warnings. +8 warnings found +one error found diff --git a/test/files/neg/t9675.flags b/test/files/neg/t9675.flags new file mode 100644 index 0000000000..85d8eb2ba2 --- /dev/null +++ b/test/files/neg/t9675.flags @@ -0,0 +1 @@ +-Xfatal-warnings diff --git a/test/files/neg/t9675.scala b/test/files/neg/t9675.scala new file mode 100644 index 0000000000..f76b74b6ac --- /dev/null +++ b/test/files/neg/t9675.scala @@ -0,0 +1,24 @@ +object Test { + case class A(x: String) + + val func1 = (x: A) => { x != "x" } + + val func2 = (x: A) => { x != "x" }: Boolean + + val func3: Function1[A, Boolean] = (x) => { x != "x" } + + val func4 = new Function1[A, Boolean] { + def apply(x: A): Boolean = { x != "x" } + } + + def method(x: A): Boolean = { x != "x" } + case class PersonInfo(rankPayEtc: Unit) + + def main(args: Array[String]) { + A("x") != "x" + + val func5: Function1[A, Boolean] = (x) => { x != "x" } + + List(A("x")).foreach((item: A) => item != "x") + } +} diff --git a/test/files/neg/trailing-commas.check b/test/files/neg/trailing-commas.check new file mode 100644 index 0000000000..e2677dc3f5 --- /dev/null +++ b/test/files/neg/trailing-commas.check @@ -0,0 +1,130 @@ +trailing-commas.scala:10: error: illegal start of simple expression +trait ArgumentExprs1 { f(23, "bar", )(Ev0, Ev1) } + ^ +trailing-commas.scala:10: error: ')' expected but '}' found. +trait ArgumentExprs1 { f(23, "bar", )(Ev0, Ev1) } + ^ +trailing-commas.scala:11: error: illegal start of simple expression +trait ArgumentExprs2 { f(23, "bar")(Ev0, Ev1, ) } + ^ +trailing-commas.scala:11: error: ')' expected but '}' found. +trait ArgumentExprs2 { f(23, "bar")(Ev0, Ev1, ) } + ^ +trailing-commas.scala:12: error: illegal start of simple expression +trait ArgumentExprs3 { new C(23, "bar", )(Ev0, Ev1) } + ^ +trailing-commas.scala:12: error: ')' expected but '}' found. +trait ArgumentExprs3 { new C(23, "bar", )(Ev0, Ev1) } + ^ +trailing-commas.scala:13: error: illegal start of simple expression +trait ArgumentExprs4 { new C(23, "bar")(Ev0, Ev1, ) } + ^ +trailing-commas.scala:13: error: ')' expected but '}' found. +trait ArgumentExprs4 { new C(23, "bar")(Ev0, Ev1, ) } + ^ +trailing-commas.scala:15: error: identifier expected but ')' found. +trait Params1 { def f(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1, ) = 1 } + ^ +trailing-commas.scala:15: error: ':' expected but '}' found. +trait Params1 { def f(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1, ) = 1 } + ^ +trailing-commas.scala:16: error: identifier expected but ')' found. +trait Params2 { def f(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1, ) = 1 } + ^ +trailing-commas.scala:16: error: ':' expected but '}' found. +trait Params2 { def f(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1, ) = 1 } + ^ +trailing-commas.scala:17: error: identifier expected but ')' found. +trait ClassParams1 { final class C(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1) } + ^ +trailing-commas.scala:17: error: ':' expected but '}' found. +trait ClassParams1 { final class C(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1) } + ^ +trailing-commas.scala:18: error: identifier expected but ')' found. +trait ClassParams2 { final class C(foo: Int, bar: String)(implicit ev0: Ev0, ev1: Ev1, ) } + ^ +trailing-commas.scala:18: error: ':' expected but '}' found. +trait ClassParams2 { final class C(foo: Int, bar: String)(implicit ev0: Ev0, ev1: Ev1, ) } + ^ +trailing-commas.scala:20: error: illegal start of simple expression +trait SimpleExpr { (23, "bar", ) } + ^ +trailing-commas.scala:20: error: ')' expected but '}' found. +trait SimpleExpr { (23, "bar", ) } + ^ +trailing-commas.scala:22: error: identifier expected but ']' found. +trait TypeArgs { def f: C[Int, String, ] } + ^ +trailing-commas.scala:22: error: ']' expected but '}' found. +trait TypeArgs { def f: C[Int, String, ] } + ^ +trailing-commas.scala:23: error: identifier expected but ']' found. +trait TypeParamClause { type C[A, B, ] } + ^ +trailing-commas.scala:23: error: ']' expected but '}' found. +trait TypeParamClause { type C[A, B, ] } + ^ +trailing-commas.scala:24: error: identifier expected but ']' found. +trait FunTypeParamClause { def f[A, B, ] } + ^ +trailing-commas.scala:24: error: ']' expected but '}' found. +trait FunTypeParamClause { def f[A, B, ] } + ^ +trailing-commas.scala:26: error: identifier expected but ')' found. +trait SimpleType { def f: (Int, String, ) } + ^ +trailing-commas.scala:26: error: ')' expected but '}' found. +trait SimpleType { def f: (Int, String, ) } + ^ +trailing-commas.scala:27: error: identifier expected but ')' found. +trait FunctionArgTypes { def f: (Int, String, ) => Boolean } + ^ +trailing-commas.scala:27: error: ')' expected but '}' found. +trait FunctionArgTypes { def f: (Int, String, ) => Boolean } + ^ +trailing-commas.scala:29: error: illegal start of simple pattern +trait SimplePattern { val (foo, bar, ) = null: Any } + ^ +trailing-commas.scala:31: error: identifier expected but '}' found. +trait ImportSelectors { import foo.{ Ev0, Ev1, } } + ^ +trailing-commas.scala:33: error: identifier expected but '}' found. +trait Import { import foo.Ev0, foo.Ev1, } + ^ +trailing-commas.scala:35: error: illegal start of simple pattern +trait ValDcl { val foo, bar, = 23 } + ^ +trailing-commas.scala:35: error: '=' expected but '}' found. +trait ValDcl { val foo, bar, = 23 } + ^ +trailing-commas.scala:36: error: illegal start of simple pattern +trait VarDcl { var foo, bar, = 23 } + ^ +trailing-commas.scala:36: error: '=' expected but '}' found. +trait VarDcl { var foo, bar, = 23 } + ^ +trailing-commas.scala:37: error: illegal start of simple pattern +trait VarDef { var foo, bar, = _ } + ^ +trailing-commas.scala:37: error: '=' expected but '}' found. +trait VarDef { var foo, bar, = _ } + ^ +trailing-commas.scala:38: error: illegal start of simple pattern +trait PatDef { val Foo(foo), Bar(bar), = bippy } + ^ +trailing-commas.scala:38: error: '=' expected but '}' found. +trait PatDef { val Foo(foo), Bar(bar), = bippy } + ^ +trailing-commas.scala:45: error: illegal start of simple expression +trait SimpleExpr2 { (23, ) } + ^ +trailing-commas.scala:45: error: ')' expected but '}' found. +trait SimpleExpr2 { (23, ) } + ^ +trailing-commas.scala:48: error: identifier expected but ')' found. +trait SimpleType2 { def f: (Int, ) } + ^ +trailing-commas.scala:48: error: ')' expected but '}' found. +trait SimpleType2 { def f: (Int, ) } + ^ +43 errors found diff --git a/test/files/neg/trailing-commas.scala b/test/files/neg/trailing-commas.scala new file mode 100644 index 0000000000..a873cb1e39 --- /dev/null +++ b/test/files/neg/trailing-commas.scala @@ -0,0 +1,56 @@ +package foo + +// Note: Using traits to get distinct errors +// (instead of sharing one single "')' expected but '}' found." at the end) + + + +//// Multi-line only cases: make sure trailing commas are only supported when multi-line + +trait ArgumentExprs1 { f(23, "bar", )(Ev0, Ev1) } +trait ArgumentExprs2 { f(23, "bar")(Ev0, Ev1, ) } +trait ArgumentExprs3 { new C(23, "bar", )(Ev0, Ev1) } +trait ArgumentExprs4 { new C(23, "bar")(Ev0, Ev1, ) } + +trait Params1 { def f(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1, ) = 1 } +trait Params2 { def f(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1, ) = 1 } +trait ClassParams1 { final class C(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1) } +trait ClassParams2 { final class C(foo: Int, bar: String)(implicit ev0: Ev0, ev1: Ev1, ) } + +trait SimpleExpr { (23, "bar", ) } + +trait TypeArgs { def f: C[Int, String, ] } +trait TypeParamClause { type C[A, B, ] } +trait FunTypeParamClause { def f[A, B, ] } + +trait SimpleType { def f: (Int, String, ) } +trait FunctionArgTypes { def f: (Int, String, ) => Boolean } + +trait SimplePattern { val (foo, bar, ) = null: Any } + +trait ImportSelectors { import foo.{ Ev0, Ev1, } } + +trait Import { import foo.Ev0, foo.Ev1, } + +trait ValDcl { val foo, bar, = 23 } +trait VarDcl { var foo, bar, = 23 } +trait VarDef { var foo, bar, = _ } +trait PatDef { val Foo(foo), Bar(bar), = bippy } + + + +//// The Tuple 1 cases + +// the Tuple1 value case: make sure that the possible "(23, )" syntax for Tuple1 doesn't compile to "23" +trait SimpleExpr2 { (23, ) } + +// the Tuple1 type case: make sure that the possible "(Int, )" syntax for Tuple1[Int] doesn't compile to "Int" +trait SimpleType2 { def f: (Int, ) } + + + +//// Test utilities +object `package` { + sealed trait Ev0; implicit object Ev0 extends Ev0 + sealed trait Ev1; implicit object Ev1 extends Ev1 +} diff --git a/test/files/neg/warn-inferred-any.check b/test/files/neg/warn-inferred-any.check index 8ad81d1529..2b321a83c9 100644 --- a/test/files/neg/warn-inferred-any.check +++ b/test/files/neg/warn-inferred-any.check @@ -9,7 +9,7 @@ warn-inferred-any.scala:17: warning: a type was inferred to be `AnyVal`; this ma ^ warn-inferred-any.scala:25: warning: a type was inferred to be `Any`; this may indicate a programming error. def za = f(1, "one") - ^ + ^ error: No warnings can be incurred under -Xfatal-warnings. four warnings found one error found diff --git a/test/files/pos/overloaded_ho_fun.scala b/test/files/pos/overloaded_ho_fun.scala index 2699ad35f8..17176715f0 100644 --- a/test/files/pos/overloaded_ho_fun.scala +++ b/test/files/pos/overloaded_ho_fun.scala @@ -49,3 +49,18 @@ object sorting { // def andThen[C](g: Bijection[B, C]): Bijection[A, C] = ??? // def compose[T](g: Bijection[T, A]) = g andThen this // } + +object SI10194 { + trait X[A] { + def map[B](f: A => B): Unit + } + + trait Y[A] extends X[A] { + def map[B](f: A => B)(implicit ordering: Ordering[B]): Unit + } + + trait Z[A] extends Y[A] + + (null: Y[Int]).map(x => x.toString) // compiled + (null: Z[Int]).map(x => x.toString) // didn't compile +} diff --git a/test/files/pos/sam_erasure_boundedwild.scala b/test/files/pos/sam_erasure_boundedwild.scala new file mode 100644 index 0000000000..1ec27e0ea4 --- /dev/null +++ b/test/files/pos/sam_erasure_boundedwild.scala @@ -0,0 +1,11 @@ +class Test { + trait Q[T] { + def toArray[T](x: Array[T]): Array[T] + def toArray(): Array[T] + } + + def crashTyper: Array[_] = { + val x : Q[_] = ??? + x.toArray // crashes while doing overload resolution + } +}
\ No newline at end of file diff --git a/test/files/pos/t10066.scala b/test/files/pos/t10066.scala new file mode 100644 index 0000000000..bef85cb08c --- /dev/null +++ b/test/files/pos/t10066.scala @@ -0,0 +1,38 @@ +package dynamicrash + +import scala.language.dynamics + +class Config + +trait Extractor[A] { + def extract(config: Config, name: String): A +} + +object Extractor { + // this has "implicit", unlike the corresponding neg test + implicit val stringExtractor = new Extractor[String] { + override def extract(config: Config, name: String): String = ??? + } +} + +class Workspace extends Dynamic { + val config: Config = new Config + + def selectDynamic[A](name: String)(implicit extractor: Extractor[A]): A = + extractor.extract(config, name) +} + +object Main { + val storage = new Workspace + + // this line works fine + // val a = storage.foo + + // this line crashes the compiler ("head of empty list") + // in ContextErrors$InferencerContextErrors$InferErrorGen$.NotWithinBoundsErrorMessage + println(storage.foo[String]) + + // this line crashes the compiler in different way ("unknown type") + // in the backend, warning: an unexpected type representation reached the compiler backend while compiling Test.scala: <error> + println(storage.foo) +} diff --git a/test/files/pos/t10154.scala b/test/files/pos/t10154.scala new file mode 100644 index 0000000000..51616b71d6 --- /dev/null +++ b/test/files/pos/t10154.scala @@ -0,0 +1,11 @@ +trait Bar2[T] + +object Test2 { + def wrap { + object Foo { + implicit def fooBar: Bar2[Foo.type] = ??? + } + + implicitly[Bar2[Foo.type]] + } +} diff --git a/test/files/pos/t10154b.scala b/test/files/pos/t10154b.scala new file mode 100644 index 0000000000..809a286c0e --- /dev/null +++ b/test/files/pos/t10154b.scala @@ -0,0 +1,16 @@ + import scala.language.existentials + + class Bar[T] + class Test { + def method = { + object Foo { + implicit def x: Bar[Foo.type] = new Bar[Foo.type] + } + type T = Foo.type + + { + object Foo + implicitly[Bar[T]] + } + } +} diff --git a/test/files/pos/t9331.scala b/test/files/pos/t9331.scala new file mode 100644 index 0000000000..00a667886f --- /dev/null +++ b/test/files/pos/t9331.scala @@ -0,0 +1,6 @@ +import scala.language.higherKinds + +trait Proxy[+T] +case class Stuff[+P[PP] <: Proxy[PP]]() { + // canEqual was incorrectly synthetized and started reporting a kind error. +} diff --git a/test/files/pos/trailing-commas.scala b/test/files/pos/trailing-commas.scala new file mode 100644 index 0000000000..b9401fe49d --- /dev/null +++ b/test/files/pos/trailing-commas.scala @@ -0,0 +1,155 @@ +package foo + +trait ArgumentExprs1 { + def f(foo: Int, bar: String)(implicit ev0: Ev0, ev1: Ev1) = 1 + f( + 23, + "bar", + )( + Ev0, + Ev1, + ) + + // test arg exprs in the presence of varargs + def g(x: Int, y: Int*) = 1 + g(1,2, + ) + g(1,List(2, 3): _*, + ) +} + +trait ArgumentExprs2 { + class C(foo: Int, bar: String)(implicit ev0: Ev0, ev1: Ev1) + new C( + 23, + "bar", + )( + Ev0, + Ev1, + ) +} + +trait Params { + def f( + foo: Int, + bar: String, + )(implicit + ev0: Ev0, + ev1: Ev1, + ) +} + +trait ClassParams { + class C( + foo: Int, + bar: String, + )(implicit + ev0: Ev0, + ev1: Ev1, + ) + + // test class params in the precense of varargs + case class D(i: Int*, + ) +} + +trait SimpleExpr1 { + def f: (Int, String) = ( + 23, + "bar", + ) + + // the Tuple1 value case, the trailing comma is ignored so the type is Int and the value 23 + def g: Int = ( + 23, + ) +} + +trait TypeArgs { + class C[A, B] + def f: C[ + Int, + String, + ] +} + +trait TypeParamClause { + class C[ + A, + B, + ] +} + +trait FunTypeParamClause { + def f[ + A, + B, + ] +} + +trait SimpleType { + def f: ( + Int, + String, + ) + + // the Tuple1 type case, the trailing comma is ignored so the type is Int and the value 23 + def g: ( + Int, + ) = 23 +} + +trait FunctionArgTypes { + def f: ( + Int, + String, + ) => Boolean +} + +trait SimplePattern { + val ( + foo, + bar, + ) = null: Any + + // test '@' syntax in patterns + Some(1) match { + case Some(x @ 1, + ) => x + } + + // test ': _*' syntax in patterns + List(1, 2, 3) match { + case List(1, 2, _ @ _*, + ) => 1 + } + + // test varargs in patterns + val List(x, y, _*, + ) = 42 :: 17 :: Nil +} + +trait ImportSelectors { + import foo.{ + Ev0, + Ev1, + } +} + +trait Bindings { + def g(f: (Int, String) => Boolean) + + g(( + foo, + bar, + ) => true) +} + +// Import, ids, ValDcl, VarDcl, VarDef, PatDef use commas, but not inside paren, bracket or brace, +// so they don't support an optional trailing comma + +// test utilities +object `package` { + sealed trait Ev0; implicit object Ev0 extends Ev0 + sealed trait Ev1; implicit object Ev1 extends Ev1 +} diff --git a/test/files/run/elidable-opt.check b/test/files/run/elidable-opt.check index 88cf98e0d1..969b9a420a 100644 --- a/test/files/run/elidable-opt.check +++ b/test/files/run/elidable-opt.check @@ -11,4 +11,4 @@ false 0 0.0 0.0 -null + diff --git a/test/files/run/elidable.check b/test/files/run/elidable.check index 88cf98e0d1..969b9a420a 100644 --- a/test/files/run/elidable.check +++ b/test/files/run/elidable.check @@ -11,4 +11,4 @@ false 0 0.0 0.0 -null + diff --git a/test/files/run/elidable.scala b/test/files/run/elidable.scala index 02785972bb..fed1c7b392 100644 --- a/test/files/run/elidable.scala +++ b/test/files/run/elidable.scala @@ -3,31 +3,36 @@ import elidable._ // runs -Xelide-below WARNING or 900 +object Fail { + def fail(msg: String): Unit = throw new IllegalStateException(s"Expected failure: $msg") +} +import Fail.fail + trait T { @elidable(FINEST) def f1() @elidable(SEVERE) def f2() - @elidable(FINEST) def f3() = assert(false, "Should have been elided.") + @elidable(FINEST) def f3() = fail("Should have been elided.") def f4() } class C extends T { def f1() = println("Good for me, I was not elided. C.f1") def f2() = println("Good for me, I was not elided. C.f2") - @elidable(FINEST) def f4() = assert(false, "Should have been elided.") + @elidable(FINEST) def f4() = fail("Should have been elided.") } object O { - @elidable(FINEST) def f1() = assert(false, "Should have been elided.") - @elidable(INFO) def f2() = assert(false, "Should have been elided.") + @elidable(FINEST) def f1() = fail("Should have been elided.") + @elidable(INFO) def f2() = fail("Should have been elided.") @elidable(SEVERE) def f3() = println("Good for me, I was not elided. O.f3") - @elidable(INFO) def f4 = assert(false, "Should have been elided (no parens).") + @elidable(INFO) def f4 = fail("Should have been elided (no parens).") } object Test { - @elidable(FINEST) def f1() = assert(false, "Should have been elided.") - @elidable(INFO) def f2() = assert(false, "Should have been elided.") + @elidable(FINEST) def f1() = fail("Should have been elided.") + @elidable(INFO) def f2() = fail("Should have been elided.") @elidable(SEVERE) def f3() = println("Good for me, I was not elided. Test.f3") - @elidable(INFO) def f4 = assert(false, "Should have been elided (no parens).") + @elidable(INFO) def f4 = fail("Should have been elided (no parens).") @elidable(FINEST) def f5() = {} @elidable(FINEST) def f6() = true @@ -38,12 +43,12 @@ object Test { @elidable(FINEST) def fb() = 1l @elidable(FINEST) def fc() = 1.0f @elidable(FINEST) def fd() = 1.0 - @elidable(FINEST) def fe() = "s" + @elidable(FINEST) def fe() = { fail("Should have been elided to empty string.") ; "hello, world" } /* variable elisions? see test/files/neg/t10068.scala - @elidable(INFO) val goner1: Int = { assert(false, "Should have been elided.") ; 42 } - @elidable(INFO) lazy val goner2: Int = { assert(false, "Should have been elided.") ; 42 } - @elidable(INFO) var goner3: Int = { assert(false, "Should have been elided.") ; 42 } + @elidable(INFO) val goner1: Int = { fail("Should have been elided.") ; 42 } + @elidable(INFO) lazy val goner2: Int = { fail("Should have been elided.") ; 42 } + @elidable(INFO) var goner3: Int = { fail("Should have been elided.") ; 42 } @elidable(INFO) var goner4: Nothing = _ */ @@ -74,6 +79,19 @@ object Test { println(fc()) println(fd()) println(fe()) + if (!fe().isEmpty) fail(s"Not empty: [${fe()}]") +/* +() +false +0 +0 +0 +0 +0 +0.0 +0.0 + // was: null +*/ // this one won't show up in the output because a call to f1 is elidable when accessed through T (c:T).f1() diff --git a/test/files/run/existentials-in-compiler.check b/test/files/run/existentials-in-compiler.check index b0d852865d..8800df0823 100644 --- a/test/files/run/existentials-in-compiler.check +++ b/test/files/run/existentials-in-compiler.check @@ -2,28 +2,28 @@ abstract trait Bippy[A <: AnyRef, B] extends AnyRef extest.Bippy[_ <: AnyRef, _] abstract trait BippyBud[A <: AnyRef, B, C <: List[A]] extends AnyRef - extest.BippyBud[A,B,C] forSome { A <: AnyRef; B; C <: List[A] } + extest.BippyBud[?0,?1,?2] forSome { type ?0 <: AnyRef; type ?1; type ?2 <: List[?0] } abstract trait BippyLike[A <: AnyRef, B <: List[A], This <: extest.BippyLike[A,B,This] with extest.Bippy[A,B]] extends AnyRef - extest.BippyLike[A,B,This] forSome { A <: AnyRef; B <: List[A]; This <: extest.BippyLike[A,B,This] with extest.Bippy[A,B] } + extest.BippyLike[?0,?1,?2] forSome { type ?0 <: AnyRef; type ?1 <: List[?0]; type ?2 <: extest.BippyLike[?0,?1,?2] with extest.Bippy[?0,?1] } abstract trait Contra[-A >: AnyRef, -B] extends AnyRef - extest.Contra[AnyRef, _] + extest.Contra[_ >: AnyRef, _] abstract trait ContraLike[-A >: AnyRef, -B >: List[A]] extends AnyRef - extest.ContraLike[A,B] forSome { -A >: AnyRef; -B >: List[A] } + extest.ContraLike[?0,?1] forSome { type ?0 >: AnyRef; type ?1 >: List[?0] } abstract trait Cov01[+A <: AnyRef, +B] extends AnyRef - extest.Cov01[AnyRef,Any] + extest.Cov01[_ <: AnyRef, _] abstract trait Cov02[+A <: AnyRef, B] extends AnyRef - extest.Cov02[AnyRef, _] + extest.Cov02[_ <: AnyRef, _] abstract trait Cov03[+A <: AnyRef, -B] extends AnyRef - extest.Cov03[AnyRef, _] + extest.Cov03[_ <: AnyRef, _] abstract trait Cov04[A <: AnyRef, +B] extends AnyRef - extest.Cov04[_ <: AnyRef, Any] + extest.Cov04[_ <: AnyRef, _] abstract trait Cov05[A <: AnyRef, B] extends AnyRef extest.Cov05[_ <: AnyRef, _] @@ -32,7 +32,7 @@ abstract trait Cov06[A <: AnyRef, -B] extends AnyRef extest.Cov06[_ <: AnyRef, _] abstract trait Cov07[-A <: AnyRef, +B] extends AnyRef - extest.Cov07[_ <: AnyRef, Any] + extest.Cov07[_ <: AnyRef, _] abstract trait Cov08[-A <: AnyRef, B] extends AnyRef extest.Cov08[_ <: AnyRef, _] @@ -41,16 +41,16 @@ abstract trait Cov09[-A <: AnyRef, -B] extends AnyRef extest.Cov09[_ <: AnyRef, _] abstract trait Cov11[+A <: AnyRef, +B <: List[_]] extends AnyRef - extest.Cov11[AnyRef,List[_]] + extest.Cov11[_ <: AnyRef, _ <: List[_]] abstract trait Cov12[+A <: AnyRef, B <: List[_]] extends AnyRef - extest.Cov12[AnyRef, _ <: List[_]] + extest.Cov12[_ <: AnyRef, _ <: List[_]] abstract trait Cov13[+A <: AnyRef, -B <: List[_]] extends AnyRef - extest.Cov13[AnyRef, _ <: List[_]] + extest.Cov13[_ <: AnyRef, _ <: List[_]] abstract trait Cov14[A <: AnyRef, +B <: List[_]] extends AnyRef - extest.Cov14[_ <: AnyRef, List[_]] + extest.Cov14[_ <: AnyRef, _ <: List[_]] abstract trait Cov15[A <: AnyRef, B <: List[_]] extends AnyRef extest.Cov15[_ <: AnyRef, _ <: List[_]] @@ -59,7 +59,7 @@ abstract trait Cov16[A <: AnyRef, -B <: List[_]] extends AnyRef extest.Cov16[_ <: AnyRef, _ <: List[_]] abstract trait Cov17[-A <: AnyRef, +B <: List[_]] extends AnyRef - extest.Cov17[_ <: AnyRef, List[_]] + extest.Cov17[_ <: AnyRef, _ <: List[_]] abstract trait Cov18[-A <: AnyRef, B <: List[_]] extends AnyRef extest.Cov18[_ <: AnyRef, _ <: List[_]] @@ -68,16 +68,16 @@ abstract trait Cov19[-A <: AnyRef, -B <: List[_]] extends AnyRef extest.Cov19[_ <: AnyRef, _ <: List[_]] abstract trait Cov21[+A, +B] extends AnyRef - extest.Cov21[Any,Any] + extest.Cov21[_, _] abstract trait Cov22[+A, B] extends AnyRef - extest.Cov22[Any, _] + extest.Cov22[_, _] abstract trait Cov23[+A, -B] extends AnyRef - extest.Cov23[Any, _] + extest.Cov23[_, _] abstract trait Cov24[A, +B] extends AnyRef - extest.Cov24[_, Any] + extest.Cov24[_, _] abstract trait Cov25[A, B] extends AnyRef extest.Cov25[_, _] @@ -86,7 +86,7 @@ abstract trait Cov26[A, -B] extends AnyRef extest.Cov26[_, _] abstract trait Cov27[-A, +B] extends AnyRef - extest.Cov27[_, Any] + extest.Cov27[_, _] abstract trait Cov28[-A, B] extends AnyRef extest.Cov28[_, _] @@ -95,43 +95,43 @@ abstract trait Cov29[-A, -B] extends AnyRef extest.Cov29[_, _] abstract trait Cov31[+A, +B, C <: (A, B)] extends AnyRef - extest.Cov31[A,B,C] forSome { +A; +B; C <: (A, B) } + extest.Cov31[?0,?1,?2] forSome { type ?0; type ?1; type ?2 <: (?0, ?1) } abstract trait Cov32[+A, B, C <: (A, B)] extends AnyRef - extest.Cov32[A,B,C] forSome { +A; B; C <: (A, B) } + extest.Cov32[?0,?1,?2] forSome { type ?0; type ?1; type ?2 <: (?0, ?1) } abstract trait Cov33[+A, -B, C <: Tuple2[A, _]] extends AnyRef - extest.Cov33[A,B,C] forSome { +A; -B; C <: Tuple2[A, _] } + extest.Cov33[?0,?1,?2] forSome { type ?0; type ?1; type ?2 <: Tuple2[?0, _] } abstract trait Cov34[A, +B, C <: (A, B)] extends AnyRef - extest.Cov34[A,B,C] forSome { A; +B; C <: (A, B) } + extest.Cov34[?0,?1,?2] forSome { type ?0; type ?1; type ?2 <: (?0, ?1) } abstract trait Cov35[A, B, C <: (A, B)] extends AnyRef - extest.Cov35[A,B,C] forSome { A; B; C <: (A, B) } + extest.Cov35[?0,?1,?2] forSome { type ?0; type ?1; type ?2 <: (?0, ?1) } abstract trait Cov36[A, -B, C <: Tuple2[A, _]] extends AnyRef - extest.Cov36[A,B,C] forSome { A; -B; C <: Tuple2[A, _] } + extest.Cov36[?0,?1,?2] forSome { type ?0; type ?1; type ?2 <: Tuple2[?0, _] } abstract trait Cov37[-A, +B, C <: Tuple2[_, B]] extends AnyRef - extest.Cov37[A,B,C] forSome { -A; +B; C <: Tuple2[_, B] } + extest.Cov37[?0,?1,?2] forSome { type ?0; type ?1; type ?2 <: Tuple2[_, ?1] } abstract trait Cov38[-A, B, C <: Tuple2[_, B]] extends AnyRef - extest.Cov38[A,B,C] forSome { -A; B; C <: Tuple2[_, B] } + extest.Cov38[?0,?1,?2] forSome { type ?0; type ?1; type ?2 <: Tuple2[_, ?1] } abstract trait Cov39[-A, -B, C <: Tuple2[_, _]] extends AnyRef extest.Cov39[_, _, _ <: Tuple2[_, _]] abstract trait Cov41[+A >: Null, +B] extends AnyRef - extest.Cov41[Any,Any] + extest.Cov41[_ >: Null, _] abstract trait Cov42[+A >: Null, B] extends AnyRef - extest.Cov42[Any, _] + extest.Cov42[_ >: Null, _] abstract trait Cov43[+A >: Null, -B] extends AnyRef - extest.Cov43[Any, _] + extest.Cov43[_ >: Null, _] abstract trait Cov44[A >: Null, +B] extends AnyRef - extest.Cov44[_ >: Null, Any] + extest.Cov44[_ >: Null, _] abstract trait Cov45[A >: Null, B] extends AnyRef extest.Cov45[_ >: Null, _] @@ -140,7 +140,7 @@ abstract trait Cov46[A >: Null, -B] extends AnyRef extest.Cov46[_ >: Null, _] abstract trait Cov47[-A >: Null, +B] extends AnyRef - extest.Cov47[_ >: Null, Any] + extest.Cov47[_ >: Null, _] abstract trait Cov48[-A >: Null, B] extends AnyRef extest.Cov48[_ >: Null, _] @@ -149,8 +149,8 @@ abstract trait Cov49[-A >: Null, -B] extends AnyRef extest.Cov49[_ >: Null, _] abstract trait Covariant[+A <: AnyRef, +B] extends AnyRef - extest.Covariant[AnyRef,Any] + extest.Covariant[_ <: AnyRef, _] abstract trait CovariantLike[+A <: AnyRef, +B <: List[A], +This <: extest.CovariantLike[A,B,This] with extest.Covariant[A,B]] extends AnyRef - extest.CovariantLike[A,B,This] forSome { +A <: AnyRef; +B <: List[A]; +This <: extest.CovariantLike[A,B,This] with extest.Covariant[A,B] } + extest.CovariantLike[?0,?1,?2] forSome { type ?0 <: AnyRef; type ?1 <: List[?0]; type ?2 <: extest.CovariantLike[?0,?1,?2] with extest.Covariant[?0,?1] } diff --git a/test/files/run/existentials-in-compiler.scala b/test/files/run/existentials-in-compiler.scala index e516eddf95..e35b7231c2 100644 --- a/test/files/run/existentials-in-compiler.scala +++ b/test/files/run/existentials-in-compiler.scala @@ -79,7 +79,7 @@ package extest { exitingTyper { clazz.info println(clazz.defString) - println(" " + classExistentialType(clazz) + "\n") + println(" " + classExistentialType(clazz.owner.typeOfThis, clazz) + "\n") } } } diff --git a/test/files/run/hash-hash-hash-hash.scala b/test/files/run/hash-hash-hash-hash.scala new file mode 100644 index 0000000000..08793871a7 --- /dev/null +++ b/test/files/run/hash-hash-hash-hash.scala @@ -0,0 +1,5 @@ +object Test { + def main(args: Array[String]): Unit = { + assert(1.##.## == 1) // was java.lang.NoSuchMethodError: java.lang.Object.$hash$hash()I + } +} diff --git a/test/files/run/iq.scala b/test/files/run/iq.scala index 0ccf67a2e9..9929f0e1a0 100644 --- a/test/files/run/iq.scala +++ b/test/files/run/iq.scala @@ -25,12 +25,18 @@ object iq { assert(q2 == qb) val qc = 42 +: q :+ 0 assert(q2 == qc) + assert(q ++ qa == qa) + val qdr = 1 +: 2 +: 3 +: 4 +: q + val qcon1 = 1 +: 2 +: q + val qcon2 = q :+ 3 :+ 4 + val qd = qcon1 ++ qcon2 + assert(qd == qdr) Console.println("q2: " + q2) Console.println("qa: " + qa) Console.println("qb: " + qb) Console.println("qc: " + qc) - + /* Test is empty and dequeue. * Expected: Head: 42 */ diff --git a/test/files/run/literals.scala b/test/files/run/literals.scala index 13fda05876..a7962e5cd9 100644 --- a/test/files/run/literals.scala +++ b/test/files/run/literals.scala @@ -6,7 +6,7 @@ object Test { - /* I add a couple of Unicode identifier tests here temporarily */ + /* I add a couple of Unicode identifier tests here "temporarily" */ def \u03b1\u03c1\u03b5\u03c4\u03b7 = "alpha rho epsilon tau eta" @@ -80,10 +80,17 @@ object Test { check_success("1e1f == 10.0f", 1e1f, 10.0f) check_success(".3f == 0.3f", .3f, 0.3f) check_success("0f == 0.0f", 0f, 0.0f) + check_success("0f == -0.000000000000000000e+00f", 0f, -0.000000000000000000e+00f) + check_success("0f == -0.000000000000000000e+00F", 0f, -0.000000000000000000e+00F) + check_success("0f == -0.0000000000000000e14f", 0f, -0.0000000000000000e14f) check_success("01.23f == 1.23f", 01.23f, 1.23f) check_success("3.14f == 3.14f", 3.14f, 3.14f) check_success("6.022e23f == 6.022e23f", 6.022e23f, 6.022e23f) check_success("09f == 9.0f", 09f, 9.0f) + check_success("1.00000017881393421514957253748434595763683319091796875001f == 1.0000001f", + 1.00000017881393421514957253748434595763683319091796875001f, + 1.0000001f) + check_success("3.4028235E38f == Float.MaxValue", 3.4028235E38f, Float.MaxValue) check_success("1.asInstanceOf[Float] == 1.0", 1.asInstanceOf[Float], 1.0f) check_success("1l.asInstanceOf[Float] == 1.0", 1l.asInstanceOf[Float], 1.0f) @@ -92,11 +99,17 @@ object Test { check_success(".3 == 0.3", .3, 0.3) check_success("0.0 == 0.0", 0.0, 0.0) check_success("0d == 0.0", 0d, 0.0) + check_success("0d == 0.000000000000000000e+00d", 0d, 0.000000000000000000e+00d) + check_success("0d == -0.000000000000000000e+00d", 0d, -0.000000000000000000e+00d) + check_success("0d == -0.000000000000000000e+00D", 0d, -0.000000000000000000e+00D) + check_success("0.0 == 0.000000000000000000e+00", 0.0, 0.000000000000000000e+00) + check_success("0.0 == -0.000000000000000000e+00", 0.0, -0.000000000000000000e+00) check_success("01.23 == 1.23", 01.23, 1.23) check_success("01.23d == 1.23d", 01.23d, 1.23d) check_success("3.14 == 3.14", 3.14, 3.14) check_success("1e-9d == 1.0e-9", 1e-9d, 1.0e-9) check_success("1e137 == 1.0e137", 1e137, 1.0e137) + check_success("1.7976931348623157e308d == Double.MaxValue", 1.7976931348623157e308d, Double.MaxValue) check_success("1.asInstanceOf[Double] == 1.0", 1.asInstanceOf[Double], 1.0) check_success("1l.asInstanceOf[Double] == 1.0", 1l.asInstanceOf[Double], 1.0) diff --git a/test/files/run/patmat-exprs.scala b/test/files/run/patmat-exprs.scala index 7ca5fd3063..d18df9c714 100644 --- a/test/files/run/patmat-exprs.scala +++ b/test/files/run/patmat-exprs.scala @@ -344,13 +344,13 @@ trait Pattern { } - case class Zero[T] (implicit num: NumericOps[T]) extends Leaf[T] { + case class Zero[T]()(implicit num: NumericOps[T]) extends Leaf[T] { def derivative(variable: Var[T]) = Zero[T] def eval(f: Any => Any) = num.zero override def toString = "0" } - case class One[T] (implicit num: NumericOps[T]) extends Leaf[T] { + case class One[T]()(implicit num: NumericOps[T]) extends Leaf[T] { def derivative(variable: Var[T]) = Zero[T] def eval(f: Any => Any) = num.one override def toString = "1" diff --git a/test/files/run/repl-colon-type.check b/test/files/run/repl-colon-type.check index 1217e8d8c2..5b7a3c7506 100644 --- a/test/files/run/repl-colon-type.check +++ b/test/files/run/repl-colon-type.check @@ -75,7 +75,7 @@ TypeRef( ) TypeRef( TypeSymbol( - sealed abstract class List[+A] extends AbstractSeq[A] with LinearSeq[A] with Product with GenericTraversableTemplate[A,List] with LinearSeqOptimized[A,List[A]] with Serializable + sealed abstract class List[+A] extends AbstractSeq[A] with LinearSeq[A] with Product with GenericTraversableTemplate[A,List] with LinearSeqOptimized[A,List[A]] with FilteredTraversableInternal[A,List[A]] with Serializable ) args = List( @@ -142,7 +142,7 @@ TypeRef( args = List( TypeRef( TypeSymbol( - sealed abstract class List[+A] extends AbstractSeq[A] with LinearSeq[A] with Product with GenericTraversableTemplate[A,List] with LinearSeqOptimized[A,List[A]] with Serializable + sealed abstract class List[+A] extends AbstractSeq[A] with LinearSeq[A] with Product with GenericTraversableTemplate[A,List] with LinearSeqOptimized[A,List[A]] with FilteredTraversableInternal[A,List[A]] with Serializable ) args = List( @@ -175,7 +175,7 @@ PolyType( args = List( TypeRef( TypeSymbol( - sealed abstract class List[+A] extends AbstractSeq[A] with LinearSeq[A] with Product with GenericTraversableTemplate[A,List] with LinearSeqOptimized[A,List[A]] with Serializable + sealed abstract class List[+A] extends AbstractSeq[A] with LinearSeq[A] with Product with GenericTraversableTemplate[A,List] with LinearSeqOptimized[A,List[A]] with FilteredTraversableInternal[A,List[A]] with Serializable ) args = List(TypeParamTypeRef(TypeParam(T <: AnyVal))) @@ -198,7 +198,7 @@ PolyType( params = List(TermSymbol(x: T), TermSymbol(y: List[U])) resultType = TypeRef( TypeSymbol( - sealed abstract class List[+A] extends AbstractSeq[A] with LinearSeq[A] with Product with GenericTraversableTemplate[A,List] with LinearSeqOptimized[A,List[A]] with Serializable + sealed abstract class List[+A] extends AbstractSeq[A] with LinearSeq[A] with Product with GenericTraversableTemplate[A,List] with LinearSeqOptimized[A,List[A]] with FilteredTraversableInternal[A,List[A]] with Serializable ) args = List(TypeParamTypeRef(TypeParam(U >: T))) diff --git a/test/files/run/t10026.check b/test/files/run/t10026.check new file mode 100644 index 0000000000..15a62794a9 --- /dev/null +++ b/test/files/run/t10026.check @@ -0,0 +1 @@ +List(1, 2, 3) diff --git a/test/files/run/t10026.scala b/test/files/run/t10026.scala new file mode 100644 index 0000000000..a56840c8c2 --- /dev/null +++ b/test/files/run/t10026.scala @@ -0,0 +1,11 @@ +import scala.reflect.runtime.universe +import scala.tools.reflect.ToolBox + +object Test { + def main(args: Array[String]): Unit = { + val classloader = getClass.getClassLoader + val toolbox = universe.runtimeMirror(classloader).mkToolBox() + println(toolbox.compile(toolbox.parse("Array(1, 2, 3).toList")).apply()) + } +} + diff --git a/test/files/run/t10072.scala b/test/files/run/t10072.scala new file mode 100644 index 0000000000..0f1dca1838 --- /dev/null +++ b/test/files/run/t10072.scala @@ -0,0 +1,18 @@ +trait T[A] { + def a: A + def foldLeft[B](zero: B, op: (B, A) => B): B = op(zero, a) + def sum[B >: A](zero: B): B +} + +class C[@specialized(Int) A](val a: A) extends T[A] { + override def sum[@specialized(Int) B >: A](zero: B): B = foldLeft(zero, (x: B, y: B) => x) +} + +object Test extends App { + def factory[T](a: T): C[T] = new C[T](a) + + assert(new C[Int](1).sum(2) == 2) + assert(new C[String]("ho").sum("hu") == "hu") + assert(factory[Int](1).sum(2) == 2) + assert(factory[String]("ho").sum("hu") == "hu") +} diff --git a/test/files/run/t10097.check b/test/files/run/t10097.check new file mode 100644 index 0000000000..0e8b96061c --- /dev/null +++ b/test/files/run/t10097.check @@ -0,0 +1,3 @@ +t10097.scala:2: warning: case classes should have a non-implicit parameter list; adapting to 'case class C()(...)' +case class C(implicit c: Int) + ^ diff --git a/test/files/run/t10097.flags b/test/files/run/t10097.flags new file mode 100644 index 0000000000..dcc59ebe32 --- /dev/null +++ b/test/files/run/t10097.flags @@ -0,0 +1 @@ +-deprecation diff --git a/test/files/run/t10097.scala b/test/files/run/t10097.scala new file mode 100644 index 0000000000..a16be897cc --- /dev/null +++ b/test/files/run/t10097.scala @@ -0,0 +1,6 @@ + +case class C(implicit c: Int) + +object Test extends App { + assert(C()(42).productArity == 0) +} diff --git a/test/files/run/t1459.check b/test/files/run/t1459.check new file mode 100644 index 0000000000..93b4c5a810 --- /dev/null +++ b/test/files/run/t1459.check @@ -0,0 +1,3 @@ +JavaPrinter: one two three +InheritingPrinter extends JavaPrinter: one two three +ScalaPrinter: onetwothree diff --git a/test/files/run/t1459/InheritingPrinter.scala b/test/files/run/t1459/InheritingPrinter.scala new file mode 100644 index 0000000000..70301307f5 --- /dev/null +++ b/test/files/run/t1459/InheritingPrinter.scala @@ -0,0 +1,6 @@ +class InheritingPrinter extends JavaPrinter { + override def doit(s: String*) { + print("InheritingPrinter extends ") + super.doit(s: _*); + } +}
\ No newline at end of file diff --git a/test/files/run/t1459/JavaPrinter.java b/test/files/run/t1459/JavaPrinter.java new file mode 100644 index 0000000000..3912ea613a --- /dev/null +++ b/test/files/run/t1459/JavaPrinter.java @@ -0,0 +1,7 @@ +public class JavaPrinter implements VarArg { + public void doit(String... s) { + System.out.print("JavaPrinter: "); + for(String str : s) + System.out.print(str + " "); + } +} diff --git a/test/files/run/t1459/ScalaPrinter.scala b/test/files/run/t1459/ScalaPrinter.scala new file mode 100644 index 0000000000..46305804c2 --- /dev/null +++ b/test/files/run/t1459/ScalaPrinter.scala @@ -0,0 +1,6 @@ +class ScalaPrinter extends VarArg { + override def doit(s: String*) = { + print("ScalaPrinter: ") + s.foreach(print _) + } +}
\ No newline at end of file diff --git a/test/files/run/t1459/Test.java b/test/files/run/t1459/Test.java new file mode 100644 index 0000000000..3cf91e2e8b --- /dev/null +++ b/test/files/run/t1459/Test.java @@ -0,0 +1,15 @@ +public class Test { + public static void main(String[] args) { + VarArg jp = new JavaPrinter(); + VarArg ip = new InheritingPrinter(); + VarArg sp = new ScalaPrinter(); + doYourThing(jp); + doYourThing(ip); + doYourThing(sp); + } + + public static void doYourThing(VarArg va) { + va.doit("one", "two", "three"); + System.out.println(); + } +} diff --git a/test/files/run/t1459/VarArg.java b/test/files/run/t1459/VarArg.java new file mode 100644 index 0000000000..7039f99e7b --- /dev/null +++ b/test/files/run/t1459/VarArg.java @@ -0,0 +1,3 @@ +public interface VarArg { + void doit(String... s); +} diff --git a/test/files/run/t1459generic.check b/test/files/run/t1459generic.check new file mode 100644 index 0000000000..346fadbc0d --- /dev/null +++ b/test/files/run/t1459generic.check @@ -0,0 +1,4 @@ +Note: t1459generic/Test.java uses unchecked or unsafe operations. +Note: Recompile with -Xlint:unchecked for details. +ab +ab diff --git a/test/files/run/t1459generic/Impl.scala b/test/files/run/t1459generic/Impl.scala new file mode 100644 index 0000000000..9234e70456 --- /dev/null +++ b/test/files/run/t1459generic/Impl.scala @@ -0,0 +1,4 @@ +class Impl extends VarargGeneric[String] { + def genericOne(x: String, arg: String): String = x + arg + def genericVar(x: String, args: String*): String = x + args.head +} diff --git a/test/files/run/t1459generic/Test.java b/test/files/run/t1459generic/Test.java new file mode 100644 index 0000000000..a97158796b --- /dev/null +++ b/test/files/run/t1459generic/Test.java @@ -0,0 +1,10 @@ +public class Test { + public static void main(String[] args) throws Exception { + VarargGeneric vg = new Impl(); + System.out.println(vg.genericOne("a", "b")); + System.out.println(vg.genericVar("a", "b")); + // should not result in java.lang.AbstractMethodError: Impl.genericVar(Ljava/lang/Object;[Ljava/lang/String;)Ljava/lang/String; + // --> genericVar needs a varargs bridge (scala -> java varargs) and a standard generics bridge + // (for comparison, including genericOne, which needs only a generics bridge) + } +} diff --git a/test/files/run/t1459generic/VarargGeneric.java b/test/files/run/t1459generic/VarargGeneric.java new file mode 100644 index 0000000000..9b37a0fe3f --- /dev/null +++ b/test/files/run/t1459generic/VarargGeneric.java @@ -0,0 +1,7 @@ +public interface VarargGeneric<T> { + String genericOne(T x, String args); + // we cannot annotate this with @SafeVarargs, because + // it's in an interface. so that's why a warning from + // javac appears in the checkfile. + String genericVar(T x, String... args); +} diff --git a/test/files/run/t4700.check b/test/files/run/t4700.check new file mode 100644 index 0000000000..ae854b959d --- /dev/null +++ b/test/files/run/t4700.check @@ -0,0 +1,44 @@ + +scala> import scala.annotation.showAsInfix +import scala.annotation.showAsInfix + +scala> class &&[T,U] +defined class $amp$amp + +scala> def foo: Int && Boolean = ??? +foo: Int && Boolean + +scala> def foo: Int && Boolean && String = ??? +foo: Int && Boolean && String + +scala> def foo: Int && (Boolean && String) = ??? +foo: Int && (Boolean && String) + +scala> @showAsInfix type Mappy[T, U] = Map[T, U] +defined type alias Mappy + +scala> def foo: Int Mappy (Boolean && String) = ??? +foo: Int Mappy (Boolean && String) + +scala> @showAsInfix(false) class ||[T,U] +defined class $bar$bar + +scala> def foo: Int || Boolean = ??? +foo: ||[Int,Boolean] + +scala> class &:[L, R] +defined class $amp$colon + +scala> def foo: Int &: String = ??? +foo: Int &: String + +scala> def foo: Int &: Boolean &: String = ??? +foo: Int &: Boolean &: String + +scala> def foo: (Int && String) &: Boolean = ??? +foo: (Int && String) &: Boolean + +scala> def foo: Int && (Boolean &: String) = ??? +foo: Int && (Boolean &: String) + +scala> :quit diff --git a/test/files/run/t4700.scala b/test/files/run/t4700.scala new file mode 100644 index 0000000000..7c02676e89 --- /dev/null +++ b/test/files/run/t4700.scala @@ -0,0 +1,22 @@ +import scala.tools.nsc.interpreter._ +import scala.tools.partest.ReplTest + +object Test extends ReplTest { + def code = """ + |import scala.annotation.showAsInfix + |class &&[T,U] + |def foo: Int && Boolean = ??? + |def foo: Int && Boolean && String = ??? + |def foo: Int && (Boolean && String) = ??? + |@showAsInfix type Mappy[T, U] = Map[T, U] + |def foo: Int Mappy (Boolean && String) = ??? + |@showAsInfix(false) class ||[T,U] + |def foo: Int || Boolean = ??? + |class &:[L, R] + |def foo: Int &: String = ??? + |def foo: Int &: Boolean &: String = ??? + |def foo: (Int && String) &: Boolean = ??? + |def foo: Int && (Boolean &: String) = ??? + |""".stripMargin +} + diff --git a/test/files/run/t5907.scala b/test/files/run/t5907.scala index a005e9fbd3..81fc43e3f5 100644 --- a/test/files/run/t5907.scala +++ b/test/files/run/t5907.scala @@ -86,7 +86,7 @@ object Test extends App { } } -case class C1(implicit x: Int) { +case class C1()(implicit x: Int) { override def toString = s"c1: $x" } case class C2()(y: Int) { diff --git a/test/files/run/t9013/Test.java b/test/files/run/t9013/Test.java new file mode 100644 index 0000000000..14152b16ac --- /dev/null +++ b/test/files/run/t9013/Test.java @@ -0,0 +1,20 @@ +import java.util.Comparator; + +public class Test { + public static void main(String[] args) { + ClassImplementsClass c = new ClassImplementsClass(); + + c.x("a", "b", "c"); + c.y("a", "b", "c"); + c.z("a", "b", "c"); + + VarargAbstractClass i = new ClassImplementsClass(); + + i.x("a", "b", "c"); + i.y("a", "b", "c"); + // System.out.println(i.z("a", "b", "c")); // still incurs a LinkageError. + // Perhaps due to Uncurry: + // > for every repeated Java parameter `x: T...' --> x: Array[T], except: + // > if T is an unbounded abstract type, replace --> x: Array[Object] + } +} diff --git a/test/files/run/t9013/test.scala b/test/files/run/t9013/test.scala new file mode 100644 index 0000000000..073f8d086f --- /dev/null +++ b/test/files/run/t9013/test.scala @@ -0,0 +1,18 @@ +import scala.annotation.varargs + +abstract class VarargAbstractClass[T] { + @varargs + def x(els: String*): Int + + @varargs + def y(els: String*): Int + + @varargs + def z(els: T*): Int +} +class ClassImplementsClass extends VarargAbstractClass[String] { + + override def x(els: String*): Int = els.length + override def y(els: String*): Int = els.length + override def z(els: String*): Int = els.length +} diff --git a/test/files/run/t9114.scala b/test/files/run/t9114.scala new file mode 100644 index 0000000000..656a5c7d8d --- /dev/null +++ b/test/files/run/t9114.scala @@ -0,0 +1,31 @@ +import annotation.unchecked + +class Test { + trait Two[A, B] + type One[A] = Two[A,A] + class View extends One[Any] + + def checkAny(x: Some[One[Any]]) = x match { // okay + case Some(_: View) => true + case _ => false + } + def checkAbstract[A](x: Some[One[A]]) = x match { // okay + case Some(_: View) => true + case _ => false + } + + def checkExistential(x: Some[One[_]]) = x match { + case Some(_: View) => true // compiler crash + case _ => false + } +} + +object Test { + def main(args: Array[String]): Unit = { + val t1 = new Test + val t2 = new Test + assert(t1.checkAny(Some(new t1.View))) + assert(t1.checkAbstract(Some(new t1.View))) + assert(t1.checkExistential(Some(new t1.View))) + } +} diff --git a/test/files/run/t9880-9881.check b/test/files/run/t9880-9881.check new file mode 100644 index 0000000000..36513e249a --- /dev/null +++ b/test/files/run/t9880-9881.check @@ -0,0 +1,36 @@ + +scala> // import in various ways + +scala> import java.util.Date +import java.util.Date + +scala> import scala.util._ +import scala.util._ + +scala> import scala.reflect.runtime.{universe => ru} +import scala.reflect.runtime.{universe=>ru} + +scala> import ru.TypeTag +import ru.TypeTag + +scala> + +scala> // show the imports + +scala> :imports + 1) import java.lang._ (...) + 2) import scala._ (...) + 3) import scala.Predef._ (...) + 4) import java.util.Date (...) + 5) import scala.util._ (...) + 6) import scala.reflect.runtime.{universe=>ru} (...) + 7) import ru.TypeTag (...) + +scala> + +scala> // should be able to define this class with the imports above + +scala> class C[T](date: Date, rand: Random, typeTag: TypeTag[T]) +defined class C + +scala> :quit diff --git a/test/files/run/t9880-9881.scala b/test/files/run/t9880-9881.scala new file mode 100644 index 0000000000..0268c8c32c --- /dev/null +++ b/test/files/run/t9880-9881.scala @@ -0,0 +1,29 @@ +import scala.tools.partest.ReplTest +import scala.tools.nsc.Settings + +object Test extends ReplTest { + + override def transformSettings(s: Settings): Settings = { + s.Yreplclassbased.value = true + s + } + + lazy val normalizeRegex = """(import\s.*)\(.*\)""".r + + override def normalize(s: String): String = normalizeRegex.replaceFirstIn(s, "$1(...)") + + def code = + """ + |// import in various ways + |import java.util.Date + |import scala.util._ + |import scala.reflect.runtime.{universe => ru} + |import ru.TypeTag + | + |// show the imports + |:imports + | + |// should be able to define this class with the imports above + |class C[T](date: Date, rand: Random, typeTag: TypeTag[T]) + """.stripMargin +} diff --git a/test/files/run/trailing-commas.check b/test/files/run/trailing-commas.check new file mode 100644 index 0000000000..0dc4335ccd --- /dev/null +++ b/test/files/run/trailing-commas.check @@ -0,0 +1,9 @@ + +scala> // test varargs in patterns + +scala> val List(x, y, _*, +) = 42 :: 17 :: Nil +x: Int = 42 +y: Int = 17 + +scala> :quit diff --git a/test/files/run/trailing-commas.scala b/test/files/run/trailing-commas.scala new file mode 100644 index 0000000000..6a7f1bb55f --- /dev/null +++ b/test/files/run/trailing-commas.scala @@ -0,0 +1,7 @@ +object Test extends scala.tools.partest.ReplTest { + def code = """ +// test varargs in patterns +val List(x, y, _*, +) = 42 :: 17 :: Nil +""" +} diff --git a/test/files/run/unit-block-hash-hash.scala b/test/files/run/unit-block-hash-hash.scala new file mode 100644 index 0000000000..2708810a71 --- /dev/null +++ b/test/files/run/unit-block-hash-hash.scala @@ -0,0 +1,12 @@ +object Ex extends Exception +object Test { + def ex: Any = throw Ex + def main(args: Array[String]): Unit = { + try { + { ex; () }.## + sys.error("no exception was thrown") + } catch { + case `Ex` => + } + } +}
\ No newline at end of file diff --git a/test/junit/scala/collection/IndexedSeqTest.scala b/test/junit/scala/collection/IndexedSeqTest.scala new file mode 100644 index 0000000000..a33849e60b --- /dev/null +++ b/test/junit/scala/collection/IndexedSeqTest.scala @@ -0,0 +1,578 @@ +package scala.collection + +import org.junit.Test +import org.junit.Ignore +import org.junit.Assert.{assertEquals, _} +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +// with the Ant JUnit runner, it's necessary to @Ignore the abstract +// classes here, or JUnit tries to instantiate them. the annotations +// can be removed when this is merged forward (TODO 2.12.x) + +/** + * base class for testing common methods on a various implementations + * + * @tparam T the collection type + * @tparam E the element type + */ +@RunWith(classOf[JUnit4]) +@Ignore +abstract class IndexedTest[T, E] { + + protected def size = 10 + + /** + * create a new instance of the test data with known values + */ + protected def underTest(size: Int): T + + /** + * returns the value of the data that is expected to be present int the original data at index {{{index}}} + * This is conceptully the same as the normal apply operation but unavaialbe due to the base types of T not supporting apply + * + * @param index the index to use for the returned value + * @return the value at the specified index + */ + protected def expectedValueAtIndex(index: Int): E + /** + * check some simple indexed access + */ + @Test def checkIndexedAccess: Unit = { + val test = underTest(size) + for (i <- 0 until size) { + assertEquals(s" at index $i", expectedValueAtIndex(i), get(test, i)) + } + } + + /** + * check simple equallity of the initial data. + * More a test of the infra that we use in this est than a full test of equallity + */ + @Test def checkEquals: Unit = { + val test1 = underTest(size) + val test2 = underTest(size) + doAssertEquals("", test1, test2) + assertNotSame(test1, test2) + expectSameContent("basic equallity", false, test1, test2, 0, size) + } + + protected def expectSameContent(txt: String, canBeSame:Boolean, orig: T, test: T, offset: Int, len: Int): Unit = { + val txtAndState = s"$txt canBeSame $canBeSame isMutableContent $isMutableContent isTakeAllSame $isTakeAllSame offset $offset len $len length(test) ${length(test)}" + val isValidSame = canBeSame && !isMutableContent && offset == 0 && len == size + if (isValidSame && isTakeAllSame) + assertSame(txtAndState, orig, test) + else + assertNotSame(txtAndState, orig, test) + assertSame(txtAndState, len, length(test)) + for (i <- 0 until len) { + assertEquals(s" $txtAndState $i $offset $len", expectedValueAtIndex(i + offset), get(test, i)) + } + } + + /** + * check the operation of {{{take}}} when the parameter is less than the size of the test data + */ + @Test def checkTakeNormal: Unit = { + val orig = underTest(size) + for (len <- 0 until size) { + val taken = take(orig, len) + expectSameContent(s" len $len", true, orig, taken, 0, len) + } + } + + /** + * check the operation of {{{slice}}} within the bounds of the source + */ + @Test def checkSliceNormal: Unit = { + val orig = underTest(size) + for ( + from <- 0 until size; + to <- from until size) { + + val sliced = slice(orig, from, to) + expectSameContent(s"from $from, to $to", true, orig, sliced, from, to - from) + } + } + + /** + * check the operation of {{{take}}} works for size of 0 + * There is a special case tha for some implementations empty will be a singleton + */ + @Test def checkTakeEmpty: Unit = { + val orig = underTest(size) + val empty1 = take(orig, 0) + val empty2 = take(orig, 0) + assertEquals(0, length(empty1)) + if (isEmptyConstant) assertSame(empty1, empty2) + } + + /** + * check the operation of {{{slice}}} works for size of 0 + * There is a special case tha for some implementations empty will be a singleton + */ + @Test def checkSliceEmpty: Unit = { + val orig = underTest(size) + for (start <- 0 until size) { + val empty1 = slice(orig, start, start) + val empty2 = slice(orig, start, start) + assertEquals(s"start $start", 0, length(empty1)) + if (isEmptyConstant) assertSame(s"start $start", empty1, empty2) + } + } + + /** + * check the operation of {{{take}}} works for the entire content + * There is a special case that for some immutable implementations they can share the result + */ + @Test def checkTakeAll: Unit = { + val orig = underTest(size) + val all = take(orig, size) + assertEquals(size, length(all)) + expectSameContent("take all", true, orig, all, 0, size) + if (isMutableContent) + assertNotSame(orig, all) + else if (isTakeAllSame) + assertSame(orig, all) + } + + /** + * check the operation of {{{slice}}} works for the entire content + * There is a special case that for some immutable implementations they can share the result + */ + @Test def checkSliceAll: Unit = { + val orig = underTest(size) + val all = slice(orig, 0, size) + assertEquals(size, length(all)) + expectSameContent("", true, orig, all, 0, size) + if (isMutableContent) + assertNotSame(orig, all) + else if (isTakeAllSame) + assertSame(orig, all) + } + + /** + * check that take operates appropriately for negative values + * take and slice should be lenient and silently ignore any data outside valid ranges + */ + @Test def checkTakeNeg: Unit = { + val orig = underTest(size) + val e = take(orig, 0) + for (len <- List(-1, -10, -99, Int.MinValue)) { + val empty = take(orig, len) + assertEquals(s"len $len", 0, length(empty)) + if (isEmptyConstant) assertSame(s"len $len", e, empty) + } + } + + /** + * check that take operates appropriately for lengths that exceed the input size + * take and slice should be lenient and silently ignore any data outside valid ranges + */ + @Test def checkTakeTooBig: Unit = { + val orig = underTest(size) + val e = take(orig, 0) + for (len <- List(size + 1, size + 10, Int.MaxValue)) { + val all = take(orig, len) + assertEquals(s"len $len", size, length(all)) + expectSameContent("", true, orig, all, 0, size) + } + } + + /** + * check that slice operates appropriately for negative start point + * take and slice should be lenient and silently ignore any data outside valid ranges + */ + @Test def checkSliceFromNeg: Unit = { + val orig = underTest(size) + for ( + from <- List(-1, -10, -99, Int.MinValue); + to <- List(-1, 0, 1, 5)) { + val start = slice(orig, from, to) + expectSameContent(s"from $from, to $to", true, orig, start, 0, Math.max(0, to)) + } + } + + /** + * check that slice operates appropriately for out of range end values + * take and slice should be lenient and silently ignore any data outside valid ranges + */ + @Test def checkSliceToTooBig: Unit = { + val orig = underTest(size) + for ( + from <- List(-1, -10, -99, Int.MinValue, 0, 1, 5); + to <- List(size + 1, size + 10, Int.MaxValue)) { + val start = slice(orig, from, to) + val realStart = Math.max(0, from) + val realLen = size - realStart + expectSameContent(s"from $from, to $to", true, orig, start, realStart, realLen) + } + } + + /** + * check that slice operates appropriately for negative values start and ends too large + * take and slice should be lenient and silently ignore any data outside valid ranges + */ + @Test def checkSliceFromNegAndToTooBig: Unit = { + val orig = underTest(size) + for ( + from <- List(-1, -10, -99, Int.MinValue); + to <- List(size + 1, size + 10, Int.MaxValue)) { + val all = slice(orig, from, to) + expectSameContent(s"from $from, to $to", true, orig, all, 0, size) + } + } + + protected def intercept[EX <: Exception : Manifest](fn: => Any) { + try { + val res = fn + fail(s"expected exception was not thrown: $res") + } catch { + case failed: AssertionError => throw failed + case e: Exception if manifest[EX].runtimeClass.isAssignableFrom(e.getClass) => + } + } + + //accessors + //the length of underTest + def length(underTest: T): Int + + //the value at index i of underTest + def get(underTest: T, i: Int): E + + def slice(underTest: T, from: Int, to: Int): T + + def take(underTest: T, size: Int): T + + //behaviour + /** is an empty value the same JVM instance */ + def isEmptyConstant: Boolean + + /** is a take / slice that results in all the data returned return this + * This is only relevant if !isMutableContent + */ + def isTakeAllSame: Boolean + + /** is the content of the collection mutable. + * If mutable there is not data sharing allowed by take/slice, if immutable then data sharing is possible + * and tested based on isTakeAllSame + */ + def isMutableContent: Boolean + + //helpers + //delegate equals check for support arrays + def doAssertEquals(txt: String, expected: T, actual: T) + +} +package IndexedTestImpl { + import java.lang.reflect.{Array => jlArray} + import java.lang.{Boolean => jlBoolean} + import java.lang.{Byte => jlByte} + import java.lang.{Short => jlShort} + import java.lang.{Integer => jlInt} + import java.lang.{Long => jlLong} + import java.lang.{Float => jlFloat} + import java.lang.{Double => jlDouble} + import java.lang.{Character => jlChar} + + import scala.collection.immutable.{StringLike, StringOps, WrappedString} + import scala.collection.mutable + import scala.runtime.BoxedUnit + trait DataProvider[E] { + protected def expectedValueAtIndex(index: Int): E = { + val someNumber = index + jlInt.bitCount(index) + toType(someNumber) + } + + protected def toType(n: Int): E + } + trait StringTestData extends DataProvider [String] { + def toType(n: Int) = n.toString + } + trait ByteTestData extends DataProvider [Byte] { + def toType(n: Int) = n.toByte + } + trait ShortTestData extends DataProvider [Short] { + def toType(n: Int) = n.toShort + } + trait IntTestData extends DataProvider [Int] { + def toType(n: Int) = n + } + trait LongTestData extends DataProvider [Long] { + def toType(n: Int) = n + } + trait FloatTestData extends DataProvider [Float] { + def toType(n: Int) = n + } + trait DoubleTestData extends DataProvider [Double] { + def toType(n: Int) = n + } + trait CharTestData extends DataProvider [Char] { + def toType(n: Int)= (n+64).toChar + } + trait BooleanTestData extends DataProvider [Boolean] { + def toType(n: Int)= (n & 0) == 0 + } + trait UnitTestData extends DataProvider [BoxedUnit] { + def toType(n: Int)= if ((n & 0) == 0) null else BoxedUnit.UNIT + } + + @Ignore + abstract class ArrayTest[E] ( + //the object or primitive type of the array + val TYPE: Class[_]) extends IndexedTest[Array[E], E]{ + override final def length(underTest: Array[E]) = underTest.length + + override def get(underTest: Array[E], i: Int) = underTest(i) + + override def slice(underTest: Array[E], from: Int, to: Int) = underTest.slice(from, to) + + override def take(underTest: Array[E], size: Int) = underTest.take(size) + + override def isEmptyConstant = false + + override def isMutableContent = true + + override def isTakeAllSame = false + + override def doAssertEquals(txt: String, expected: Array[E], actual: Array[E]): Unit = { + assertEquals(txt, expected.mkString("'"), actual.mkString("'")) + } + + override def underTest(size: Int): Array[E] = { + val res = jlArray.newInstance(TYPE, size) + for (i <- 0 until size) { + jlArray.set(res, i, expectedValueAtIndex(i)) + } + res.asInstanceOf[Array[E]] + } + } + + + @Ignore + abstract class WrappedArrayTest[E]( + //the object or primitive type of the array + val TYPE: Class[_]) extends IndexedTest[mutable.WrappedArray[E], E] with DataProvider[E]{ + import mutable.WrappedArray + override final def length(underTest: WrappedArray[E]) = underTest.length + + override def get(underTest: WrappedArray[E], i: Int) = underTest(i) + + override def slice(underTest: WrappedArray[E], from: Int, to: Int) = underTest.slice(from, to) + + override def take(underTest: WrappedArray[E], size: Int) = underTest.take(size) + + override def isEmptyConstant = false + + override def isMutableContent = true + + override def isTakeAllSame = false + + override def doAssertEquals(txt: String, expected: WrappedArray[E], actual: WrappedArray[E]): Unit = { + assertEquals(txt, expected.mkString("'"), actual.mkString("'")) + } + + override def underTest(size: Int): WrappedArray[E] = { + val res = jlArray.newInstance(TYPE, size) + for (i <- 0 until size) { + jlArray.set(res, i, expectedValueAtIndex(i)) + } + WrappedArray.make(res.asInstanceOf[Array[E]]) + } + } + + //construct the data using java as much as possible to avoid invalidating the test + + @Ignore + abstract class MutableIndexedSeqTest[T <: mutable.Seq[E], E] extends IndexedTest[T, E] with DataProvider[E]{ + override final def length(underTest: T) = underTest.length + + override def get(underTest: T, i: Int) = underTest(i) + + override def slice(underTest: T, from: Int, to: Int) = underTest.slice(from, to).asInstanceOf[T] + + override def take(underTest: T, size: Int) = underTest.take(size).asInstanceOf[T] + + override def isEmptyConstant = false + + override def isMutableContent = true + + override def isTakeAllSame = true + + override def doAssertEquals(txt: String, expected: T, actual: T): Unit = { + assertEquals(txt, expected, actual) + } + + def createEmpty(size: Int) : T + + override protected def underTest(size: Int): T = { + val res:T = createEmpty(size) + for (i <- 0 until size) + res(i) = expectedValueAtIndex(i) + res + } + + } + @Ignore + abstract class ImmutableIndexedSeqTest[T <: SeqLike[E, T], E] extends IndexedTest[T, E] with DataProvider[E] { + override final def length(underTest: T) = underTest.length + + override def get(underTest: T, i: Int) = underTest(i) + + override def slice(underTest: T, from: Int, to: Int) = underTest.slice(from, to) + + override def take(underTest: T, size: Int) = underTest.take(size) + + override def isEmptyConstant = false + + override def isMutableContent = false + + override def isTakeAllSame = true + + override def doAssertEquals(txt: String, expected: T, actual: T): Unit = { + assertEquals(txt, expected, actual) + } + + } + @Ignore + abstract class StringOpsBaseTest extends IndexedTest[StringOps, Char] with DataProvider[Char] { + override final def length(underTest: StringOps) = underTest.length + + override def get(underTest: StringOps, i: Int) = underTest(i) + + override def slice(underTest: StringOps, from: Int, to: Int) = underTest.slice(from, to) + + override def take(underTest: StringOps, size: Int) = underTest.take(size) + + override def isEmptyConstant = false + + override def isMutableContent = false + + override def isTakeAllSame = false + + override def doAssertEquals(txt: String, expected: StringOps, actual: StringOps): Unit = { + assertEquals(txt, expected, actual) + } + + } + + class BooleanArrayTest extends ArrayTest[Boolean](jlBoolean.TYPE) with BooleanTestData + class ByteArrayTest extends ArrayTest[Byte](jlByte.TYPE) with ByteTestData + class ShortArrayTest extends ArrayTest[Short](jlShort.TYPE) with ShortTestData + class IntArrayTest extends ArrayTest[Int](jlInt.TYPE) with IntTestData + class LongArrayTest extends ArrayTest[Long](jlLong.TYPE) with LongTestData + class DoubleArrayTest extends ArrayTest[Double](jlDouble.TYPE) with DoubleTestData + class FloatArrayTest extends ArrayTest[Float](jlFloat.TYPE) with FloatTestData + class CharArrayTest extends ArrayTest[Char](jlChar.TYPE) with CharTestData + class UnitArrayTest extends ArrayTest[BoxedUnit](null) with UnitTestData { + override def underTest(size: Int): Array[BoxedUnit] = { + val res = new Array[Unit](size) + for (i <- 0 until size) { + jlArray.set(res, i, expectedValueAtIndex(i)) + } + res.asInstanceOf[Array[BoxedUnit]] + } + } + class RefArrayTest extends ArrayTest[String](classOf[String]) with StringTestData + + class BooleanWrappedArrayTest extends WrappedArrayTest[Boolean](jlBoolean.TYPE) with BooleanTestData + class ByteWrappedArrayTest extends WrappedArrayTest[Byte](jlByte.TYPE) with ByteTestData + class ShortWrappedArrayTest extends WrappedArrayTest[Short](jlShort.TYPE) with ShortTestData + class IntWrappedArrayTest extends WrappedArrayTest[Int](jlInt.TYPE) with IntTestData + class LongWrappedArrayTest extends WrappedArrayTest[Long](jlLong.TYPE) with LongTestData + class DoubleWrappedArrayTest extends WrappedArrayTest[Double](jlDouble.TYPE) with DoubleTestData + class FloatWrappedArrayTest extends WrappedArrayTest[Float](jlFloat.TYPE) with FloatTestData + class CharWrappedArrayTest extends WrappedArrayTest[Char](jlChar.TYPE) with CharTestData + class UnitWrappedArrayTest extends WrappedArrayTest[BoxedUnit](null) with UnitTestData { + import mutable.WrappedArray + override def underTest(size: Int): WrappedArray[BoxedUnit] = { + val res = new Array[Unit](size) + for (i <- 0 until size) { + jlArray.set(res, i, expectedValueAtIndex(i)) + } + WrappedArray.make(res.asInstanceOf[Array[Unit]]) + } + } + class RefWrappedArrayTest extends WrappedArrayTest[String](classOf[String]) with StringTestData + + class ListBufferTest extends MutableIndexedSeqTest[mutable.ListBuffer[String], String] with StringTestData { + import mutable.ListBuffer + override def createEmpty(size: Int): ListBuffer[String] = { + val res = new ListBuffer[String] + for (i <- 0 until size) + res += expectedValueAtIndex(i) + res + } + } + class ArraySeqTest extends MutableIndexedSeqTest[mutable.ArraySeq[String], String] with StringTestData { + import mutable.ArraySeq + override def createEmpty(size: Int): ArraySeq[String] = { + val res = new ArraySeq[String](size) + for (i <- 0 until size) + res (i) = expectedValueAtIndex(i) + res + } + } + class ArrayBufferTest extends MutableIndexedSeqTest[mutable.ArrayBuffer[String], String] with StringTestData { + import mutable.ArrayBuffer + override def createEmpty(size: Int): ArrayBuffer[String] = { + val res = new ArrayBuffer[String](size) + for (i <- 0 until size) + res += expectedValueAtIndex(i) + res + } + } + class ListTest extends ImmutableIndexedSeqTest[List[String], String] with StringTestData { + + override protected def underTest(size: Int): List[String] = { + var res:List[String] = Nil + var index = size-1 + while (index >= 0) { + res = expectedValueAtIndex(index) :: res + index -= 1 + } + res + } + } + class StringBuilderTest extends MutableIndexedSeqTest[StringBuilder, Char] with CharTestData { + + override def createEmpty(size: Int): StringBuilder = new StringBuilder(size) + + override protected def underTest(size: Int): StringBuilder = { + var res = createEmpty(size) + for (i <- 0 until size) + res += expectedValueAtIndex(i) + res + } + } + class StringOpsTest extends StringOpsBaseTest with CharTestData { + + override protected def underTest(size: Int): StringOps = { + var res = new StringBuilder(size) + for (i <- 0 until size) + res += expectedValueAtIndex(i) + res.toString + } + } + class WrappedStringTest extends ImmutableIndexedSeqTest[WrappedString, Char] with CharTestData { + + override def isTakeAllSame: Boolean = false + + override protected def underTest(size: Int): WrappedString = { + var res = new StringBuilder(size) + for (i <- 0 until size) + res += expectedValueAtIndex(i) + new WrappedString(res.toString) + } + } + class VectorTest extends ImmutableIndexedSeqTest[Vector[String], String] with StringTestData { + + override protected def underTest(size: Int): Vector[String] = { + var res = Vector.newBuilder[String] + for (i <- 0 until size) + res += expectedValueAtIndex(i) + res.result() + } + } + +} diff --git a/test/junit/scala/collection/concurrent/TrieMapTest.scala b/test/junit/scala/collection/concurrent/TrieMapTest.scala new file mode 100644 index 0000000000..ed67f3e9a9 --- /dev/null +++ b/test/junit/scala/collection/concurrent/TrieMapTest.scala @@ -0,0 +1,54 @@ +package scala.collection.concurrent + +import org.junit.{Assert, Test} + +class TrieMapTest { + + private def check[T](result2: List[Any])(f: TrieMap[String, String] => TraversableOnce[Any]) = { + val m = TrieMap[String, String]() + val values = f(m) + m.put("k", "v") + Assert.assertEquals(Nil, values.toList) + Assert.assertEquals(result2, f(m).toList) + } + + @Test + def iterator(): Unit = { + check(List(("k", "v")))(_.iterator) + } + + @Test + def values(): Unit = { + check(List("v"))(_.values) + } + + @Test + def valuesIterator(): Unit = { + check(List("v"))(_.valuesIterator) + } + + @Test + def keySet(): Unit = { + check(List("k"))(_.keySet) + } + + @Test + def keysIterator(): Unit = { + check(List("k"))(_.keysIterator) + } + + @Test + def keys(): Unit = { + check(List("k"))(_.keys) + } + + @Test + def filterKeys(): Unit = { + check(List(("k", "v")))(_.filterKeys(_ => true)) + } + + @Test + def mapValues(): Unit = { + check(List(("k", "v")))(_.mapValues(x => x)) + } +} diff --git a/test/junit/scala/collection/immutable/StreamTest.scala b/test/junit/scala/collection/immutable/StreamTest.scala index 7046525f37..61f7b792e8 100644 --- a/test/junit/scala/collection/immutable/StreamTest.scala +++ b/test/junit/scala/collection/immutable/StreamTest.scala @@ -117,4 +117,10 @@ class StreamTest { assert((0 #:: 1 #:: s) == (0 #:: 1 #:: s), "Cons of referentially identical streams should be equal (==)") assert((0 #:: 1 #:: s) equals (0 #:: 1 #:: s), "Cons of referentially identical streams should be equal (equals)") } + + @Test + def t9886: Unit = { + assertEquals(Stream(None, Some(1)), None #:: Stream(Some(1))) + assertEquals(Stream(None, Some(1)), Stream(None) #::: Stream(Some(1))) + } } diff --git a/test/junit/scala/collection/mutable/BitSetTest.scala b/test/junit/scala/collection/mutable/BitSetTest.scala index 84b906e8d5..f0a0ef5d75 100644 --- a/test/junit/scala/collection/mutable/BitSetTest.scala +++ b/test/junit/scala/collection/mutable/BitSetTest.scala @@ -7,7 +7,7 @@ import org.junit.runners.JUnit4 @RunWith(classOf[JUnit4]) class BitSetTest { // Test for SI-8910 - @Test def capacityExpansionTest() { + @Test def capacityExpansionTest(): Unit = { val bitSet = BitSet.empty val size = bitSet.toBitMask.length bitSet ^= bitSet @@ -20,7 +20,7 @@ class BitSetTest { assert(bitSet.toBitMask.length == size, "Capacity of bitset changed after &~=") } - @Test def test_SI8917() { + @Test def test_SI8917(): Unit = { val bigBitSet = BitSet(1, 100, 10000) val littleBitSet = BitSet(100) bigBitSet &= littleBitSet @@ -29,10 +29,16 @@ class BitSetTest { assert(littleBitSet.toBitMask.length < bigBitSet.toBitMask.length, "Needlessly extended the size of bitset on &=") } - @Test def test_SI8647() { + @Test def test_SI8647(): Unit = { val bs = BitSet() bs.map(_ + 1) // Just needs to compile val xs = bs: SortedSet[Int] xs.map(_ + 1) // Also should compile (did before) } + + @Test def t10164(): Unit = { + val bs = BitSet() + val last = (bs ++ (0 to 128)).last // Just needs not to throw + assert(last == 128) + } } diff --git a/test/junit/scala/reflect/internal/NamesTest.scala b/test/junit/scala/reflect/internal/NamesTest.scala index 549c10abed..d6182e7cca 100644 --- a/test/junit/scala/reflect/internal/NamesTest.scala +++ b/test/junit/scala/reflect/internal/NamesTest.scala @@ -92,4 +92,29 @@ class NamesTest { assert(h1 string_== h2) assert(h1 string_== h1y) } + + @Test + def pos(): Unit = { + def check(nameString: String, sub: String) = { + val name = TermName(nameString) + val javaResult = name.toString.indexOf(sub) match { case -1 => name.length case x => x } + val nameResult = name.pos(sub) + assertEquals(javaResult, nameResult) + if (sub.length == 1) { + val nameResultChar = name.pos(sub.head) + assertEquals(javaResult, nameResultChar) + } + } + + check("a", "a") // was "String index out of range: 1 + check("a", "b") + check("a", "ab") + check("a", "ba") + check("ab", "a") + check("ab", "b") + check("ab", "ab") + check("ab", "ba") + check("", "x") + check("", "xy") + } } diff --git a/test/junit/scala/reflect/internal/PrintersTest.scala b/test/junit/scala/reflect/internal/PrintersTest.scala index 722062ba21..c7cfe0dfbb 100644 --- a/test/junit/scala/reflect/internal/PrintersTest.scala +++ b/test/junit/scala/reflect/internal/PrintersTest.scala @@ -556,7 +556,7 @@ class ClassPrintTest { @Test def testCaseClassWithParams3 = assertPrintedCode(sm""" |{ - | case class X(implicit x: scala.Int, s: scala.Predef.String); + | case class X()(implicit x: scala.Int, s: scala.Predef.String); | () |}""") diff --git a/test/junit/scala/tools/nsc/classpath/JrtClassPathTest.scala b/test/junit/scala/tools/nsc/classpath/JrtClassPathTest.scala new file mode 100644 index 0000000000..2c3c5134da --- /dev/null +++ b/test/junit/scala/tools/nsc/classpath/JrtClassPathTest.scala @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014 Contributor. All rights reserved. + */ +package scala.tools.nsc.classpath + +import org.junit.Assert._ +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +import scala.tools.nsc.Settings +import scala.tools.nsc.backend.jvm.AsmUtils +import scala.tools.nsc.util.ClassPath +import scala.tools.util.PathResolver + +@RunWith(classOf[JUnit4]) +class JrtClassPathTest { + + @Test def lookupJavaClasses(): Unit = { + val specVersion = scala.util.Properties.javaSpecVersion + // Run the test using the JDK8 or 9 provider for rt.jar depending on the platform the test is running on. + val cp: ClassPath = + if (specVersion == "" || specVersion == "1.8") { + val settings = new Settings() + val resolver = new PathResolver(settings) + val elements = new ClassPathFactory(settings).classesInPath(resolver.Calculated.javaBootClassPath) + AggregateClassPath(elements) + } + else JrtClassPath().get + + assertEquals(Nil, cp.classes("")) + assertTrue(cp.packages("java").toString, cp.packages("java").exists(_.name == "java.lang")) + assertTrue(cp.classes("java.lang").exists(_.name == "Object")) + val jl_Object = cp.classes("java.lang").find(_.name == "Object").get + assertEquals("java/lang/Object", AsmUtils.classFromBytes(jl_Object.file.toByteArray).name) + assertTrue(cp.list("java.lang").packages.exists(_.name == "java.lang.annotation")) + assertTrue(cp.list("java.lang").classesAndSources.exists(_.name == "Object")) + assertTrue(cp.findClass("java.lang.Object").isDefined) + assertTrue(cp.findClassFile("java.lang.Object").isDefined) + } +} diff --git a/test/partest b/test/partest deleted file mode 100755 index d74176aa8a..0000000000 --- a/test/partest +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/env bash -# -############################################################################## -# Scala test runner 2.10.0 -############################################################################## -# (c) 2002-2013 LAMP/EPFL -# -# This is free software; see the distribution for copying conditions. -# There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. -############################################################################## - -findScalaHome () { - # see SI-2092 and SI-5792 - local source="${BASH_SOURCE[0]}" - while [ -h "$source" ] ; do - local linked="$(readlink "$source")" - local dir="$( cd -P $(dirname "$source") && cd -P $(dirname "$linked") && pwd )" - source="$dir/$(basename "$linked")" - done - ( ( cd -P "$(dirname "$source")/.." > /dev/null ) && pwd ) -} - -# Use tput to detect color-capable terminal. -# (note: I have found that on Cygwin, the script sometimes dies here. -# it doesn't happen from the Cygwin prompt when ssh'ing in to -# jenkins-worker-windows-publish, only when I make a Jenkins job -# that runs this script. I don't know why. it may have to do with -# which bash flags are set (-e? -x?) and with bash flags propagating -# from one script to another? not sure. anyway, normally in a CI -# context we run partest through sbt, not through this script, so I'm -# not investigating further for now.) -term_colors=$(tput colors 2>/dev/null) -if [[ $? == 0 ]] && [[ $term_colors -gt 2 ]]; then - git_diff_options="--color=always --word-diff" - color_opts="-Dpartest.colors=$term_colors" -else - unset color_opts - git_diff_options="--nocolor" -fi - -cygwin=false; -darwin=false; -case "`uname`" in - CYGWIN*) cygwin=true ;; - Darwin*) darwin=true ;; -esac - -# Finding the root folder for this Scala distribution -SCALA_HOME="$(findScalaHome)" - -if $cygwin; then - SCALA_HOME=`cygpath --windows --short-name "$SCALA_HOME"` - SCALA_HOME=`cygpath --unix "$SCALA_HOME"` -fi - -# Let sbt construct the classpath used to run partest (downloading partest from maven if necessary) -# PARTEST_CLASSPATH="" -if [ -z "$PARTEST_CLASSPATH" ] ; then - if [ ! -f "$SCALA_HOME/build/quick/partest.properties" ] ; then - (cd "$SCALA_HOME" && sbt dist/mkQuick) # builds quick, downloads partest and writes classpath to build/quick/partest.properties - fi - - PARTEST_CLASSPATH=$( cat "$SCALA_HOME/build/quick/partest.properties" | grep partest.classpath | sed -e 's/\\:/:/g' | cut -f2- -d= ) - - # sanity check, disabled to save time - # $( javap -classpath $PARTEST_CLASSPATH scala.tools.partest.nest.NestRunner &> /dev/null ) || unset PARTEST_CLASSPATH -fi - -# if [ -z "$PARTEST_CLASSPATH" ] ; then -# if [ -f "$SCALA_HOME/lib/scala-partest.jar" ] ; then -# for ext in "$SCALA_HOME"/lib/* ; do -# if [ -z "$PARTEST_CLASSPATH" ] ; then -# PARTEST_CLASSPATH="$ext" -# else -# PARTEST_CLASSPATH="$PARTEST_CLASSPATH:$ext" -# fi -# done -# elif [ -f "$SCALA_HOME/build/pack/lib/scala-partest.jar" ] ; then -# for lib in `echo "scala-partest scala-library scala-parser-combinators scala-xml scala-reflect scala-compiler diffutils"`; do -# ext="$SCALA_HOME/build/pack/lib/$lib.jar" -# if [ -z "$PARTEST_CLASSPATH" ] ; then -# PARTEST_CLASSPATH="$ext" -# else -# PARTEST_CLASSPATH="$PARTEST_CLASSPATH:$ext" -# fi -# done -# fi -# fi - -# Locate a javac command -# Try: JAVA_HOME, sibling to specific JAVACMD, or PATH -# Don't fail if there is no javac, since not all tests require it. -if [ -z "$JAVAC_CMD" ] ; then - if [ -n "${JAVA_HOME}" ] && [ -f "${JAVA_HOME}/bin/javac" ] ; then - JAVAC_CMD="${JAVA_HOME}/bin/javac" - fi - if [ -z "$JAVAC_CMD" ] && [ -n "$JAVACMD" ] ; then - JDIR=`dirname "${JAVACMD}"` - JAVAC_CMD="${JDIR}/javac" - fi - if [ -z "$JAVAC_CMD" ] ; then - JAVAC_CMD=`type -p javac` - fi -fi - -if $cygwin; then - if [ "$OS" = "Windows_NT" ] && cygpath -m .>/dev/null 2>/dev/null ; then - format=mixed - else - format=windows - fi - if [ -n "${JAVA_HOME}" ] ; then - JAVA_HOME=`cygpath --$format "$JAVA_HOME"` - fi - if [ -n "${JAVACMD}" ] ; then - JAVACMD=`cygpath --$format "$JAVACMD"` - fi - if [ -n "${JAVAC_CMD}" ] ; then - JAVAC_CMD=`cygpath --$format "$JAVAC_CMD"` - fi - SCALA_HOME=`cygpath --$format "$SCALA_HOME"` -fi - -# last arg wins, so if JAVA_OPTS already contains -Xmx or -Xms the -# supplied argument will be used. -JAVA_OPTS="-Xmx1024M -Xms64M $JAVA_OPTS" - -# the sbt task doesn't supply any options by default, -# so don't do that here either -- note that you may want to pass -optimise -# to mimic what happens during nightlies. -# [ -n "$SCALAC_OPTS" ] || SCALAC_OPTS="-deprecation" - -partestDebugStr="" -if [ ! -z "${PARTEST_DEBUG}" ] ; then - partestDebugStr="-Dpartest.debug=${PARTEST_DEBUG}" -fi - -# note that variables which may intentionally be empty must not -# be quoted: otherwise an empty string will appear as a command line -# argument, and java will think that is the program to run. -"${JAVACMD:=java}" \ - $JAVA_OPTS -cp "$PARTEST_CLASSPATH" \ - ${partestDebugStr} \ - ${color_opts} \ - -Dfile.encoding=UTF-8 \ - -Dscala.home="${SCALA_HOME}" \ - -Dpartest.javacmd="${JAVACMD}" \ - -Dpartest.java_opts="${JAVA_OPTS}" \ - -Dpartest.scalac_opts="${SCALAC_OPTS}" \ - -Dpartest.javac_cmd="${JAVAC_CMD}" \ - scala.tools.partest.nest.ConsoleRunner "$@" diff --git a/test/scalacheck/duration.scala b/test/scalacheck/duration.scala index 89cb9ff955..fc861b886a 100644 --- a/test/scalacheck/duration.scala +++ b/test/scalacheck/duration.scala @@ -32,7 +32,10 @@ object DurationTest extends Properties("Division of Duration by Long") { val genClose = for { a <- weightedLong if a != 0 - b <- choose(Long.MaxValue / a - 10, Long.MaxValue / a + 10) + val center = Long.MaxValue / a + b <- + if (center - 10 < center + 10) choose(center - 10, center + 10) + else choose(center + 10, center - 10) // deal with overflow if abs(a) == 1 } yield (a, b) val genBorderline = diff --git a/test/simplejson/__init__.py b/test/simplejson/__init__.py deleted file mode 100644 index d5b4d39913..0000000000 --- a/test/simplejson/__init__.py +++ /dev/null @@ -1,318 +0,0 @@ -r"""JSON (JavaScript Object Notation) <http://json.org> is a subset of -JavaScript syntax (ECMA-262 3rd edition) used as a lightweight data -interchange format. - -:mod:`simplejson` exposes an API familiar to users of the standard library -:mod:`marshal` and :mod:`pickle` modules. It is the externally maintained -version of the :mod:`json` library contained in Python 2.6, but maintains -compatibility with Python 2.4 and Python 2.5 and (currently) has -significant performance advantages, even without using the optional C -extension for speedups. - -Encoding basic Python object hierarchies:: - - >>> import simplejson as json - >>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}]) - '["foo", {"bar": ["baz", null, 1.0, 2]}]' - >>> print json.dumps("\"foo\bar") - "\"foo\bar" - >>> print json.dumps(u'\u1234') - "\u1234" - >>> print json.dumps('\\') - "\\" - >>> print json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True) - {"a": 0, "b": 0, "c": 0} - >>> from StringIO import StringIO - >>> io = StringIO() - >>> json.dump(['streaming API'], io) - >>> io.getvalue() - '["streaming API"]' - -Compact encoding:: - - >>> import simplejson as json - >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':')) - '[1,2,3,{"4":5,"6":7}]' - -Pretty printing:: - - >>> import simplejson as json - >>> s = json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=4) - >>> print '\n'.join([l.rstrip() for l in s.splitlines()]) - { - "4": 5, - "6": 7 - } - -Decoding JSON:: - - >>> import simplejson as json - >>> obj = [u'foo', {u'bar': [u'baz', None, 1.0, 2]}] - >>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]') == obj - True - >>> json.loads('"\\"foo\\bar"') == u'"foo\x08ar' - True - >>> from StringIO import StringIO - >>> io = StringIO('["streaming API"]') - >>> json.load(io)[0] == 'streaming API' - True - -Specializing JSON object decoding:: - - >>> import simplejson as json - >>> def as_complex(dct): - ... if '__complex__' in dct: - ... return complex(dct['real'], dct['imag']) - ... return dct - ... - >>> json.loads('{"__complex__": true, "real": 1, "imag": 2}', - ... object_hook=as_complex) - (1+2j) - >>> import decimal - >>> json.loads('1.1', parse_float=decimal.Decimal) == decimal.Decimal('1.1') - True - -Specializing JSON object encoding:: - - >>> import simplejson as json - >>> def encode_complex(obj): - ... if isinstance(obj, complex): - ... return [obj.real, obj.imag] - ... raise TypeError(repr(o) + " is not JSON serializable") - ... - >>> json.dumps(2 + 1j, default=encode_complex) - '[2.0, 1.0]' - >>> json.JSONEncoder(default=encode_complex).encode(2 + 1j) - '[2.0, 1.0]' - >>> ''.join(json.JSONEncoder(default=encode_complex).iterencode(2 + 1j)) - '[2.0, 1.0]' - - -Using simplejson.tool from the shell to validate and pretty-print:: - - $ echo '{"json":"obj"}' | python -m simplejson.tool - { - "json": "obj" - } - $ echo '{ 1.2:3.4}' | python -m simplejson.tool - Expecting property name: line 1 column 2 (char 2) -""" -__version__ = '2.0.9' -__all__ = [ - 'dump', 'dumps', 'load', 'loads', - 'JSONDecoder', 'JSONEncoder', -] - -__author__ = 'Bob Ippolito <bob@redivi.com>' - -from decoder import JSONDecoder -from encoder import JSONEncoder - -_default_encoder = JSONEncoder( - skipkeys=False, - ensure_ascii=True, - check_circular=True, - allow_nan=True, - indent=None, - separators=None, - encoding='utf-8', - default=None, -) - -def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, - allow_nan=True, cls=None, indent=None, separators=None, - encoding='utf-8', default=None, **kw): - """Serialize ``obj`` as a JSON formatted stream to ``fp`` (a - ``.write()``-supporting file-like object). - - If ``skipkeys`` is true then ``dict`` keys that are not basic types - (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``) - will be skipped instead of raising a ``TypeError``. - - If ``ensure_ascii`` is false, then the some chunks written to ``fp`` - may be ``unicode`` instances, subject to normal Python ``str`` to - ``unicode`` coercion rules. Unless ``fp.write()`` explicitly - understands ``unicode`` (as in ``codecs.getwriter()``) this is likely - to cause an error. - - If ``check_circular`` is false, then the circular reference check - for container types will be skipped and a circular reference will - result in an ``OverflowError`` (or worse). - - If ``allow_nan`` is false, then it will be a ``ValueError`` to - serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) - in strict compliance of the JSON specification, instead of using the - JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). - - If ``indent`` is a non-negative integer, then JSON array elements and object - members will be pretty-printed with that indent level. An indent level - of 0 will only insert newlines. ``None`` is the most compact representation. - - If ``separators`` is an ``(item_separator, dict_separator)`` tuple - then it will be used instead of the default ``(', ', ': ')`` separators. - ``(',', ':')`` is the most compact JSON representation. - - ``encoding`` is the character encoding for str instances, default is UTF-8. - - ``default(obj)`` is a function that should return a serializable version - of obj or raise TypeError. The default simply raises TypeError. - - To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the - ``.default()`` method to serialize additional types), specify it with - the ``cls`` kwarg. - - """ - # cached encoder - if (not skipkeys and ensure_ascii and - check_circular and allow_nan and - cls is None and indent is None and separators is None and - encoding == 'utf-8' and default is None and not kw): - iterable = _default_encoder.iterencode(obj) - else: - if cls is None: - cls = JSONEncoder - iterable = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii, - check_circular=check_circular, allow_nan=allow_nan, indent=indent, - separators=separators, encoding=encoding, - default=default, **kw).iterencode(obj) - # could accelerate with writelines in some versions of Python, at - # a debuggability cost - for chunk in iterable: - fp.write(chunk) - - -def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, - allow_nan=True, cls=None, indent=None, separators=None, - encoding='utf-8', default=None, **kw): - """Serialize ``obj`` to a JSON formatted ``str``. - - If ``skipkeys`` is false then ``dict`` keys that are not basic types - (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``) - will be skipped instead of raising a ``TypeError``. - - If ``ensure_ascii`` is false, then the return value will be a - ``unicode`` instance subject to normal Python ``str`` to ``unicode`` - coercion rules instead of being escaped to an ASCII ``str``. - - If ``check_circular`` is false, then the circular reference check - for container types will be skipped and a circular reference will - result in an ``OverflowError`` (or worse). - - If ``allow_nan`` is false, then it will be a ``ValueError`` to - serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) in - strict compliance of the JSON specification, instead of using the - JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). - - If ``indent`` is a non-negative integer, then JSON array elements and - object members will be pretty-printed with that indent level. An indent - level of 0 will only insert newlines. ``None`` is the most compact - representation. - - If ``separators`` is an ``(item_separator, dict_separator)`` tuple - then it will be used instead of the default ``(', ', ': ')`` separators. - ``(',', ':')`` is the most compact JSON representation. - - ``encoding`` is the character encoding for str instances, default is UTF-8. - - ``default(obj)`` is a function that should return a serializable version - of obj or raise TypeError. The default simply raises TypeError. - - To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the - ``.default()`` method to serialize additional types), specify it with - the ``cls`` kwarg. - - """ - # cached encoder - if (not skipkeys and ensure_ascii and - check_circular and allow_nan and - cls is None and indent is None and separators is None and - encoding == 'utf-8' and default is None and not kw): - return _default_encoder.encode(obj) - if cls is None: - cls = JSONEncoder - return cls( - skipkeys=skipkeys, ensure_ascii=ensure_ascii, - check_circular=check_circular, allow_nan=allow_nan, indent=indent, - separators=separators, encoding=encoding, default=default, - **kw).encode(obj) - - -_default_decoder = JSONDecoder(encoding=None, object_hook=None) - - -def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None, - parse_int=None, parse_constant=None, **kw): - """Deserialize ``fp`` (a ``.read()``-supporting file-like object containing - a JSON document) to a Python object. - - If the contents of ``fp`` is encoded with an ASCII based encoding other - than utf-8 (e.g. latin-1), then an appropriate ``encoding`` name must - be specified. Encodings that are not ASCII based (such as UCS-2) are - not allowed, and should be wrapped with - ``codecs.getreader(fp)(encoding)``, or simply decoded to a ``unicode`` - object and passed to ``loads()`` - - ``object_hook`` is an optional function that will be called with the - result of any object literal decode (a ``dict``). The return value of - ``object_hook`` will be used instead of the ``dict``. This feature - can be used to implement custom decoders (e.g. JSON-RPC class hinting). - - To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` - kwarg. - - """ - return loads(fp.read(), - encoding=encoding, cls=cls, object_hook=object_hook, - parse_float=parse_float, parse_int=parse_int, - parse_constant=parse_constant, **kw) - - -def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None, - parse_int=None, parse_constant=None, **kw): - """Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON - document) to a Python object. - - If ``s`` is a ``str`` instance and is encoded with an ASCII based encoding - other than utf-8 (e.g. latin-1) then an appropriate ``encoding`` name - must be specified. Encodings that are not ASCII based (such as UCS-2) - are not allowed and should be decoded to ``unicode`` first. - - ``object_hook`` is an optional function that will be called with the - result of any object literal decode (a ``dict``). The return value of - ``object_hook`` will be used instead of the ``dict``. This feature - can be used to implement custom decoders (e.g. JSON-RPC class hinting). - - ``parse_float``, if specified, will be called with the string - of every JSON float to be decoded. By default this is equivalent to - float(num_str). This can be used to use another datatype or parser - for JSON floats (e.g. decimal.Decimal). - - ``parse_int``, if specified, will be called with the string - of every JSON int to be decoded. By default this is equivalent to - int(num_str). This can be used to use another datatype or parser - for JSON integers (e.g. float). - - ``parse_constant``, if specified, will be called with one of the - following strings: -Infinity, Infinity, NaN, null, true, false. - This can be used to raise an exception if invalid JSON numbers - are encountered. - - To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` - kwarg. - - """ - if (cls is None and encoding is None and object_hook is None and - parse_int is None and parse_float is None and - parse_constant is None and not kw): - return _default_decoder.decode(s) - if cls is None: - cls = JSONDecoder - if object_hook is not None: - kw['object_hook'] = object_hook - if parse_float is not None: - kw['parse_float'] = parse_float - if parse_int is not None: - kw['parse_int'] = parse_int - if parse_constant is not None: - kw['parse_constant'] = parse_constant - return cls(encoding=encoding, **kw).decode(s) diff --git a/test/simplejson/decoder.py b/test/simplejson/decoder.py deleted file mode 100644 index b769ea486c..0000000000 --- a/test/simplejson/decoder.py +++ /dev/null @@ -1,354 +0,0 @@ -"""Implementation of JSONDecoder -""" -import re -import sys -import struct - -from simplejson.scanner import make_scanner -try: - from simplejson._speedups import scanstring as c_scanstring -except ImportError: - c_scanstring = None - -__all__ = ['JSONDecoder'] - -FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL - -def _floatconstants(): - _BYTES = '7FF80000000000007FF0000000000000'.decode('hex') - if sys.byteorder != 'big': - _BYTES = _BYTES[:8][::-1] + _BYTES[8:][::-1] - nan, inf = struct.unpack('dd', _BYTES) - return nan, inf, -inf - -NaN, PosInf, NegInf = _floatconstants() - - -def linecol(doc, pos): - lineno = doc.count('\n', 0, pos) + 1 - if lineno == 1: - colno = pos - else: - colno = pos - doc.rindex('\n', 0, pos) - return lineno, colno - - -def errmsg(msg, doc, pos, end=None): - # Note that this function is called from _speedups - lineno, colno = linecol(doc, pos) - if end is None: - #fmt = '{0}: line {1} column {2} (char {3})' - #return fmt.format(msg, lineno, colno, pos) - fmt = '%s: line %d column %d (char %d)' - return fmt % (msg, lineno, colno, pos) - endlineno, endcolno = linecol(doc, end) - #fmt = '{0}: line {1} column {2} - line {3} column {4} (char {5} - {6})' - #return fmt.format(msg, lineno, colno, endlineno, endcolno, pos, end) - fmt = '%s: line %d column %d - line %d column %d (char %d - %d)' - return fmt % (msg, lineno, colno, endlineno, endcolno, pos, end) - - -_CONSTANTS = { - '-Infinity': NegInf, - 'Infinity': PosInf, - 'NaN': NaN, -} - -STRINGCHUNK = re.compile(r'(.*?)(["\\\x00-\x1f])', FLAGS) -BACKSLASH = { - '"': u'"', '\\': u'\\', '/': u'/', - 'b': u'\b', 'f': u'\f', 'n': u'\n', 'r': u'\r', 't': u'\t', -} - -DEFAULT_ENCODING = "utf-8" - -def py_scanstring(s, end, encoding=None, strict=True, _b=BACKSLASH, _m=STRINGCHUNK.match): - """Scan the string s for a JSON string. End is the index of the - character in s after the quote that started the JSON string. - Unescapes all valid JSON string escape sequences and raises ValueError - on attempt to decode an invalid string. If strict is False then literal - control characters are allowed in the string. - - Returns a tuple of the decoded string and the index of the character in s - after the end quote.""" - if encoding is None: - encoding = DEFAULT_ENCODING - chunks = [] - _append = chunks.append - begin = end - 1 - while 1: - chunk = _m(s, end) - if chunk is None: - raise ValueError( - errmsg("Unterminated string starting at", s, begin)) - end = chunk.end() - content, terminator = chunk.groups() - # Content is contains zero or more unescaped string characters - if content: - if not isinstance(content, unicode): - content = unicode(content, encoding) - _append(content) - # Terminator is the end of string, a literal control character, - # or a backslash denoting that an escape sequence follows - if terminator == '"': - break - elif terminator != '\\': - if strict: - msg = "Invalid control character %r at" % (terminator,) - #msg = "Invalid control character {0!r} at".format(terminator) - raise ValueError(errmsg(msg, s, end)) - else: - _append(terminator) - continue - try: - esc = s[end] - except IndexError: - raise ValueError( - errmsg("Unterminated string starting at", s, begin)) - # If not a unicode escape sequence, must be in the lookup table - if esc != 'u': - try: - char = _b[esc] - except KeyError: - msg = "Invalid \\escape: " + repr(esc) - raise ValueError(errmsg(msg, s, end)) - end += 1 - else: - # Unicode escape sequence - esc = s[end + 1:end + 5] - next_end = end + 5 - if len(esc) != 4: - msg = "Invalid \\uXXXX escape" - raise ValueError(errmsg(msg, s, end)) - uni = int(esc, 16) - # Check for surrogate pair on UCS-4 systems - if 0xd800 <= uni <= 0xdbff and sys.maxunicode > 65535: - msg = "Invalid \\uXXXX\\uXXXX surrogate pair" - if not s[end + 5:end + 7] == '\\u': - raise ValueError(errmsg(msg, s, end)) - esc2 = s[end + 7:end + 11] - if len(esc2) != 4: - raise ValueError(errmsg(msg, s, end)) - uni2 = int(esc2, 16) - uni = 0x10000 + (((uni - 0xd800) << 10) | (uni2 - 0xdc00)) - next_end += 6 - char = unichr(uni) - end = next_end - # Append the unescaped character - _append(char) - return u''.join(chunks), end - - -# Use speedup if available -scanstring = c_scanstring or py_scanstring - -WHITESPACE = re.compile(r'[ \t\n\r]*', FLAGS) -WHITESPACE_STR = ' \t\n\r' - -def JSONObject((s, end), encoding, strict, scan_once, object_hook, _w=WHITESPACE.match, _ws=WHITESPACE_STR): - pairs = {} - # Use a slice to prevent IndexError from being raised, the following - # check will raise a more specific ValueError if the string is empty - nextchar = s[end:end + 1] - # Normally we expect nextchar == '"' - if nextchar != '"': - if nextchar in _ws: - end = _w(s, end).end() - nextchar = s[end:end + 1] - # Trivial empty object - if nextchar == '}': - return pairs, end + 1 - elif nextchar != '"': - raise ValueError(errmsg("Expecting property name", s, end)) - end += 1 - while True: - key, end = scanstring(s, end, encoding, strict) - - # To skip some function call overhead we optimize the fast paths where - # the JSON key separator is ": " or just ":". - if s[end:end + 1] != ':': - end = _w(s, end).end() - if s[end:end + 1] != ':': - raise ValueError(errmsg("Expecting : delimiter", s, end)) - - end += 1 - - try: - if s[end] in _ws: - end += 1 - if s[end] in _ws: - end = _w(s, end + 1).end() - except IndexError: - pass - - try: - value, end = scan_once(s, end) - except StopIteration: - raise ValueError(errmsg("Expecting object", s, end)) - pairs[key] = value - - try: - nextchar = s[end] - if nextchar in _ws: - end = _w(s, end + 1).end() - nextchar = s[end] - except IndexError: - nextchar = '' - end += 1 - - if nextchar == '}': - break - elif nextchar != ',': - raise ValueError(errmsg("Expecting , delimiter", s, end - 1)) - - try: - nextchar = s[end] - if nextchar in _ws: - end += 1 - nextchar = s[end] - if nextchar in _ws: - end = _w(s, end + 1).end() - nextchar = s[end] - except IndexError: - nextchar = '' - - end += 1 - if nextchar != '"': - raise ValueError(errmsg("Expecting property name", s, end - 1)) - - if object_hook is not None: - pairs = object_hook(pairs) - return pairs, end - -def JSONArray((s, end), scan_once, _w=WHITESPACE.match, _ws=WHITESPACE_STR): - values = [] - nextchar = s[end:end + 1] - if nextchar in _ws: - end = _w(s, end + 1).end() - nextchar = s[end:end + 1] - # Look-ahead for trivial empty array - if nextchar == ']': - return values, end + 1 - _append = values.append - while True: - try: - value, end = scan_once(s, end) - except StopIteration: - raise ValueError(errmsg("Expecting object", s, end)) - _append(value) - nextchar = s[end:end + 1] - if nextchar in _ws: - end = _w(s, end + 1).end() - nextchar = s[end:end + 1] - end += 1 - if nextchar == ']': - break - elif nextchar != ',': - raise ValueError(errmsg("Expecting , delimiter", s, end)) - - try: - if s[end] in _ws: - end += 1 - if s[end] in _ws: - end = _w(s, end + 1).end() - except IndexError: - pass - - return values, end - -class JSONDecoder(object): - """Simple JSON <http://json.org> decoder - - Performs the following translations in decoding by default: - - +---------------+-------------------+ - | JSON | Python | - +===============+===================+ - | object | dict | - +---------------+-------------------+ - | array | list | - +---------------+-------------------+ - | string | unicode | - +---------------+-------------------+ - | number (int) | int, long | - +---------------+-------------------+ - | number (real) | float | - +---------------+-------------------+ - | true | True | - +---------------+-------------------+ - | false | False | - +---------------+-------------------+ - | null | None | - +---------------+-------------------+ - - It also understands ``NaN``, ``Infinity``, and ``-Infinity`` as - their corresponding ``float`` values, which is outside the JSON spec. - - """ - - def __init__(self, encoding=None, object_hook=None, parse_float=None, - parse_int=None, parse_constant=None, strict=True): - """``encoding`` determines the encoding used to interpret any ``str`` - objects decoded by this instance (utf-8 by default). It has no - effect when decoding ``unicode`` objects. - - Note that currently only encodings that are a superset of ASCII work, - strings of other encodings should be passed in as ``unicode``. - - ``object_hook``, if specified, will be called with the result - of every JSON object decoded and its return value will be used in - place of the given ``dict``. This can be used to provide custom - deserializations (e.g. to support JSON-RPC class hinting). - - ``parse_float``, if specified, will be called with the string - of every JSON float to be decoded. By default this is equivalent to - float(num_str). This can be used to use another datatype or parser - for JSON floats (e.g. decimal.Decimal). - - ``parse_int``, if specified, will be called with the string - of every JSON int to be decoded. By default this is equivalent to - int(num_str). This can be used to use another datatype or parser - for JSON integers (e.g. float). - - ``parse_constant``, if specified, will be called with one of the - following strings: -Infinity, Infinity, NaN. - This can be used to raise an exception if invalid JSON numbers - are encountered. - - """ - self.encoding = encoding - self.object_hook = object_hook - self.parse_float = parse_float or float - self.parse_int = parse_int or int - self.parse_constant = parse_constant or _CONSTANTS.__getitem__ - self.strict = strict - self.parse_object = JSONObject - self.parse_array = JSONArray - self.parse_string = scanstring - self.scan_once = make_scanner(self) - - def decode(self, s, _w=WHITESPACE.match): - """Return the Python representation of ``s`` (a ``str`` or ``unicode`` - instance containing a JSON document) - - """ - obj, end = self.raw_decode(s, idx=_w(s, 0).end()) - end = _w(s, end).end() - if end != len(s): - raise ValueError(errmsg("Extra data", s, end, len(s))) - return obj - - def raw_decode(self, s, idx=0): - """Decode a JSON document from ``s`` (a ``str`` or ``unicode`` beginning - with a JSON document) and return a 2-tuple of the Python - representation and the index in ``s`` where the document ended. - - This can be used to decode a JSON document from a string that may - have extraneous data at the end. - - """ - try: - obj, end = self.scan_once(s, idx) - except StopIteration: - raise ValueError("No JSON object could be decoded") - return obj, end diff --git a/test/simplejson/encoder.py b/test/simplejson/encoder.py deleted file mode 100644 index cf58290366..0000000000 --- a/test/simplejson/encoder.py +++ /dev/null @@ -1,440 +0,0 @@ -"""Implementation of JSONEncoder -""" -import re - -try: - from simplejson._speedups import encode_basestring_ascii as c_encode_basestring_ascii -except ImportError: - c_encode_basestring_ascii = None -try: - from simplejson._speedups import make_encoder as c_make_encoder -except ImportError: - c_make_encoder = None - -ESCAPE = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t]') -ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])') -HAS_UTF8 = re.compile(r'[\x80-\xff]') -ESCAPE_DCT = { - '\\': '\\\\', - '"': '\\"', - '\b': '\\b', - '\f': '\\f', - '\n': '\\n', - '\r': '\\r', - '\t': '\\t', -} -for i in range(0x20): - #ESCAPE_DCT.setdefault(chr(i), '\\u{0:04x}'.format(i)) - ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,)) - -# Assume this produces an infinity on all machines (probably not guaranteed) -INFINITY = float('1e66666') -FLOAT_REPR = repr - -def encode_basestring(s): - """Return a JSON representation of a Python string - - """ - def replace(match): - return ESCAPE_DCT[match.group(0)] - return '"' + ESCAPE.sub(replace, s) + '"' - - -def py_encode_basestring_ascii(s): - """Return an ASCII-only JSON representation of a Python string - - """ - if isinstance(s, str) and HAS_UTF8.search(s) is not None: - s = s.decode('utf-8') - def replace(match): - s = match.group(0) - try: - return ESCAPE_DCT[s] - except KeyError: - n = ord(s) - if n < 0x10000: - #return '\\u{0:04x}'.format(n) - return '\\u%04x' % (n,) - else: - # surrogate pair - n -= 0x10000 - s1 = 0xd800 | ((n >> 10) & 0x3ff) - s2 = 0xdc00 | (n & 0x3ff) - #return '\\u{0:04x}\\u{1:04x}'.format(s1, s2) - return '\\u%04x\\u%04x' % (s1, s2) - return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"' - - -encode_basestring_ascii = c_encode_basestring_ascii or py_encode_basestring_ascii - -class JSONEncoder(object): - """Extensible JSON <http://json.org> encoder for Python data structures. - - Supports the following objects and types by default: - - +-------------------+---------------+ - | Python | JSON | - +===================+===============+ - | dict | object | - +-------------------+---------------+ - | list, tuple | array | - +-------------------+---------------+ - | str, unicode | string | - +-------------------+---------------+ - | int, long, float | number | - +-------------------+---------------+ - | True | true | - +-------------------+---------------+ - | False | false | - +-------------------+---------------+ - | None | null | - +-------------------+---------------+ - - To extend this to recognize other objects, subclass and implement a - ``.default()`` method with another method that returns a serializable - object for ``o`` if possible, otherwise it should call the superclass - implementation (to raise ``TypeError``). - - """ - item_separator = ', ' - key_separator = ': ' - def __init__(self, skipkeys=False, ensure_ascii=True, - check_circular=True, allow_nan=True, sort_keys=False, - indent=None, separators=None, encoding='utf-8', default=None): - """Constructor for JSONEncoder, with sensible defaults. - - If skipkeys is false, then it is a TypeError to attempt - encoding of keys that are not str, int, long, float or None. If - skipkeys is True, such items are simply skipped. - - If ensure_ascii is true, the output is guaranteed to be str - objects with all incoming unicode characters escaped. If - ensure_ascii is false, the output will be unicode object. - - If check_circular is true, then lists, dicts, and custom encoded - objects will be checked for circular references during encoding to - prevent an infinite recursion (which would cause an OverflowError). - Otherwise, no such check takes place. - - If allow_nan is true, then NaN, Infinity, and -Infinity will be - encoded as such. This behavior is not JSON specification compliant, - but is consistent with most JavaScript based encoders and decoders. - Otherwise, it will be a ValueError to encode such floats. - - If sort_keys is true, then the output of dictionaries will be - sorted by key; this is useful for regression tests to ensure - that JSON serializations can be compared on a day-to-day basis. - - If indent is a non-negative integer, then JSON array - elements and object members will be pretty-printed with that - indent level. An indent level of 0 will only insert newlines. - None is the most compact representation. - - If specified, separators should be a (item_separator, key_separator) - tuple. The default is (', ', ': '). To get the most compact JSON - representation you should specify (',', ':') to eliminate whitespace. - - If specified, default is a function that gets called for objects - that can't otherwise be serialized. It should return a JSON encodable - version of the object or raise a ``TypeError``. - - If encoding is not None, then all input strings will be - transformed into unicode using that encoding prior to JSON-encoding. - The default is UTF-8. - - """ - - self.skipkeys = skipkeys - self.ensure_ascii = ensure_ascii - self.check_circular = check_circular - self.allow_nan = allow_nan - self.sort_keys = sort_keys - self.indent = indent - if separators is not None: - self.item_separator, self.key_separator = separators - if default is not None: - self.default = default - self.encoding = encoding - - def default(self, o): - """Implement this method in a subclass such that it returns - a serializable object for ``o``, or calls the base implementation - (to raise a ``TypeError``). - - For example, to support arbitrary iterators, you could - implement default like this:: - - def default(self, o): - try: - iterable = iter(o) - except TypeError: - pass - else: - return list(iterable) - return JSONEncoder.default(self, o) - - """ - raise TypeError(repr(o) + " is not JSON serializable") - - def encode(self, o): - """Return a JSON string representation of a Python data structure. - - >>> JSONEncoder().encode({"foo": ["bar", "baz"]}) - '{"foo": ["bar", "baz"]}' - - """ - # This is for extremely simple cases and benchmarks. - if isinstance(o, basestring): - if isinstance(o, str): - _encoding = self.encoding - if (_encoding is not None - and not (_encoding == 'utf-8')): - o = o.decode(_encoding) - if self.ensure_ascii: - return encode_basestring_ascii(o) - else: - return encode_basestring(o) - # This doesn't pass the iterator directly to ''.join() because the - # exceptions aren't as detailed. The list call should be roughly - # equivalent to the PySequence_Fast that ''.join() would do. - chunks = self.iterencode(o, _one_shot=True) - if not isinstance(chunks, (list, tuple)): - chunks = list(chunks) - return ''.join(chunks) - - def iterencode(self, o, _one_shot=False): - """Encode the given object and yield each string - representation as available. - - For example:: - - for chunk in JSONEncoder().iterencode(bigobject): - mysocket.write(chunk) - - """ - if self.check_circular: - markers = {} - else: - markers = None - if self.ensure_ascii: - _encoder = encode_basestring_ascii - else: - _encoder = encode_basestring - if self.encoding != 'utf-8': - def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding): - if isinstance(o, str): - o = o.decode(_encoding) - return _orig_encoder(o) - - def floatstr(o, allow_nan=self.allow_nan, _repr=FLOAT_REPR, _inf=INFINITY, _neginf=-INFINITY): - # Check for specials. Note that this type of test is processor- and/or - # platform-specific, so do tests which don't depend on the internals. - - if o != o: - text = 'NaN' - elif o == _inf: - text = 'Infinity' - elif o == _neginf: - text = '-Infinity' - else: - return _repr(o) - - if not allow_nan: - raise ValueError( - "Out of range float values are not JSON compliant: " + - repr(o)) - - return text - - - if _one_shot and c_make_encoder is not None and not self.indent and not self.sort_keys: - _iterencode = c_make_encoder( - markers, self.default, _encoder, self.indent, - self.key_separator, self.item_separator, self.sort_keys, - self.skipkeys, self.allow_nan) - else: - _iterencode = _make_iterencode( - markers, self.default, _encoder, self.indent, floatstr, - self.key_separator, self.item_separator, self.sort_keys, - self.skipkeys, _one_shot) - return _iterencode(o, 0) - -def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot, - ## HACK: hand-optimized bytecode; turn globals into locals - False=False, - True=True, - ValueError=ValueError, - basestring=basestring, - dict=dict, - float=float, - id=id, - int=int, - isinstance=isinstance, - list=list, - long=long, - str=str, - tuple=tuple, - ): - - def _iterencode_list(lst, _current_indent_level): - if not lst: - yield '[]' - return - if markers is not None: - markerid = id(lst) - if markerid in markers: - raise ValueError("Circular reference detected") - markers[markerid] = lst - buf = '[' - if _indent is not None: - _current_indent_level += 1 - newline_indent = '\n' + (' ' * (_indent * _current_indent_level)) - separator = _item_separator + newline_indent - buf += newline_indent - else: - newline_indent = None - separator = _item_separator - first = True - for value in lst: - if first: - first = False - else: - buf = separator - if isinstance(value, basestring): - yield buf + _encoder(value) - elif value is None: - yield buf + 'null' - elif value is True: - yield buf + 'true' - elif value is False: - yield buf + 'false' - elif isinstance(value, (int, long)): - yield buf + str(value) - elif isinstance(value, float): - yield buf + _floatstr(value) - else: - yield buf - if isinstance(value, (list, tuple)): - chunks = _iterencode_list(value, _current_indent_level) - elif isinstance(value, dict): - chunks = _iterencode_dict(value, _current_indent_level) - else: - chunks = _iterencode(value, _current_indent_level) - for chunk in chunks: - yield chunk - if newline_indent is not None: - _current_indent_level -= 1 - yield '\n' + (' ' * (_indent * _current_indent_level)) - yield ']' - if markers is not None: - del markers[markerid] - - def _iterencode_dict(dct, _current_indent_level): - if not dct: - yield '{}' - return - if markers is not None: - markerid = id(dct) - if markerid in markers: - raise ValueError("Circular reference detected") - markers[markerid] = dct - yield '{' - if _indent is not None: - _current_indent_level += 1 - newline_indent = '\n' + (' ' * (_indent * _current_indent_level)) - item_separator = _item_separator + newline_indent - yield newline_indent - else: - newline_indent = None - item_separator = _item_separator - first = True - if _sort_keys: - items = dct.items() - items.sort(key=lambda kv: kv[0]) - else: - items = dct.iteritems() - for key, value in items: - if isinstance(key, basestring): - pass - # JavaScript is weakly typed for these, so it makes sense to - # also allow them. Many encoders seem to do something like this. - elif isinstance(key, float): - key = _floatstr(key) - elif key is True: - key = 'true' - elif key is False: - key = 'false' - elif key is None: - key = 'null' - elif isinstance(key, (int, long)): - key = str(key) - elif _skipkeys: - continue - else: - raise TypeError("key " + repr(key) + " is not a string") - if first: - first = False - else: - yield item_separator - yield _encoder(key) - yield _key_separator - if isinstance(value, basestring): - yield _encoder(value) - elif value is None: - yield 'null' - elif value is True: - yield 'true' - elif value is False: - yield 'false' - elif isinstance(value, (int, long)): - yield str(value) - elif isinstance(value, float): - yield _floatstr(value) - else: - if isinstance(value, (list, tuple)): - chunks = _iterencode_list(value, _current_indent_level) - elif isinstance(value, dict): - chunks = _iterencode_dict(value, _current_indent_level) - else: - chunks = _iterencode(value, _current_indent_level) - for chunk in chunks: - yield chunk - if newline_indent is not None: - _current_indent_level -= 1 - yield '\n' + (' ' * (_indent * _current_indent_level)) - yield '}' - if markers is not None: - del markers[markerid] - - def _iterencode(o, _current_indent_level): - if isinstance(o, basestring): - yield _encoder(o) - elif o is None: - yield 'null' - elif o is True: - yield 'true' - elif o is False: - yield 'false' - elif isinstance(o, (int, long)): - yield str(o) - elif isinstance(o, float): - yield _floatstr(o) - elif isinstance(o, (list, tuple)): - for chunk in _iterencode_list(o, _current_indent_level): - yield chunk - elif isinstance(o, dict): - for chunk in _iterencode_dict(o, _current_indent_level): - yield chunk - else: - if markers is not None: - markerid = id(o) - if markerid in markers: - raise ValueError("Circular reference detected") - markers[markerid] = o - o = _default(o) - for chunk in _iterencode(o, _current_indent_level): - yield chunk - if markers is not None: - del markers[markerid] - - return _iterencode diff --git a/test/simplejson/scanner.py b/test/simplejson/scanner.py deleted file mode 100644 index adbc6ec979..0000000000 --- a/test/simplejson/scanner.py +++ /dev/null @@ -1,65 +0,0 @@ -"""JSON token scanner -""" -import re -try: - from simplejson._speedups import make_scanner as c_make_scanner -except ImportError: - c_make_scanner = None - -__all__ = ['make_scanner'] - -NUMBER_RE = re.compile( - r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?', - (re.VERBOSE | re.MULTILINE | re.DOTALL)) - -def py_make_scanner(context): - parse_object = context.parse_object - parse_array = context.parse_array - parse_string = context.parse_string - match_number = NUMBER_RE.match - encoding = context.encoding - strict = context.strict - parse_float = context.parse_float - parse_int = context.parse_int - parse_constant = context.parse_constant - object_hook = context.object_hook - - def _scan_once(string, idx): - try: - nextchar = string[idx] - except IndexError: - raise StopIteration - - if nextchar == '"': - return parse_string(string, idx + 1, encoding, strict) - elif nextchar == '{': - return parse_object((string, idx + 1), encoding, strict, _scan_once, object_hook) - elif nextchar == '[': - return parse_array((string, idx + 1), _scan_once) - elif nextchar == 'n' and string[idx:idx + 4] == 'null': - return None, idx + 4 - elif nextchar == 't' and string[idx:idx + 4] == 'true': - return True, idx + 4 - elif nextchar == 'f' and string[idx:idx + 5] == 'false': - return False, idx + 5 - - m = match_number(string, idx) - if m is not None: - integer, frac, exp = m.groups() - if frac or exp: - res = parse_float(integer + (frac or '') + (exp or '')) - else: - res = parse_int(integer) - return res, m.end() - elif nextchar == 'N' and string[idx:idx + 3] == 'NaN': - return parse_constant('NaN'), idx + 3 - elif nextchar == 'I' and string[idx:idx + 8] == 'Infinity': - return parse_constant('Infinity'), idx + 8 - elif nextchar == '-' and string[idx:idx + 9] == '-Infinity': - return parse_constant('-Infinity'), idx + 9 - else: - raise StopIteration - - return _scan_once - -make_scanner = c_make_scanner or py_make_scanner diff --git a/test/simplejson/tool.py b/test/simplejson/tool.py deleted file mode 100644 index 90443317b2..0000000000 --- a/test/simplejson/tool.py +++ /dev/null @@ -1,37 +0,0 @@ -r"""Command-line tool to validate and pretty-print JSON - -Usage:: - - $ echo '{"json":"obj"}' | python -m simplejson.tool - { - "json": "obj" - } - $ echo '{ 1.2:3.4}' | python -m simplejson.tool - Expecting property name: line 1 column 2 (char 2) - -""" -import sys -import simplejson - -def main(): - if len(sys.argv) == 1: - infile = sys.stdin - outfile = sys.stdout - elif len(sys.argv) == 2: - infile = open(sys.argv[1], 'rb') - outfile = sys.stdout - elif len(sys.argv) == 3: - infile = open(sys.argv[1], 'rb') - outfile = open(sys.argv[2], 'wb') - else: - raise SystemExit(sys.argv[0] + " [infile [outfile]]") - try: - obj = simplejson.load(infile) - except ValueError, e: - raise SystemExit(e) - simplejson.dump(obj, outfile, sort_keys=True, indent=4) - outfile.write('\n') - - -if __name__ == '__main__': - main() diff --git a/tools/partest-ack b/tools/partest-ack deleted file mode 100755 index ab722e3b1c..0000000000 --- a/tools/partest-ack +++ /dev/null @@ -1,131 +0,0 @@ -#!/usr/bin/env bash -# -# wrapper around partest for fine-grained test selection via ack - -declare quiet failed update partest_debug -declare cotouched since sortCommand -declare -a ack_args partest_args scalac_args -declare -r standard_ack_args="--noenv -s --java --scala --type-add=scala:ext:flags,check --files-with-matches" - -partest_args=( --show-diff ) -bindir="$(cd "$(dirname "$0")" && pwd)" -base="$bindir/.." -cd "$base" || { echo "Could not change to base directory $base" && exit 1; } -filesdir="test/files" -sortCommand="sort -u" -partestPaths="$bindir/partest-paths" - -[[ -x "$partestPaths" ]] || { echo "Cannot find partest-paths in $partestPaths" && exit 1; } - -[[ $# -gt 0 ]] || { - cat <<EOM -Usage: $0 <regex> [-dfquvp] [ack options] - - -f pass --failed to partest - -q pass --terse to partest - -u pass --update-check to partest - -p <path> select tests appearing in commits where <path> was also modified - -s <time> select tests touched since <time> (git format, e.g. 1.month.ago) - -r run tests in random order - -Given a regular expression (and optionally, any arguments accepted by ack) -runs all the tests for which any associated file matches the regex. Associated -files include .check and .flags files. Tests in directories will match if any -file matches. A file can match the regex by its contents or by its name. - -You must have ack version 2.12+ installed: http://beyondgrep.com/ack-2.12-single-file - -Examples: - - > tools/partest-ack 'case (class|object) Baz' - % testsWithMatchingPaths ... 0 - % testsWithMatchingCode ... 3 - # 3 tests to run. - - > tools/partest-ack -s 12.hours.ago - % testsTouchedSinceGitTime ... 33 - # 33 tests to run. - - > tools/partest-ack -p src/library/scala/Enumeration.scala - % testsModifiedInSameCommit ... 80 - # 80 tests to run. - - > tools/partest-ack -f - % tests-which-failed ... 42 - # 42 tests to run. - - > tools/partest-ack "kinds of the type arguments" - % testsWithMatchingPaths ... 0 - % testsWithMatchingCode ... 6 - # 6 tests to run. -EOM - - exit 0 -} - -while getopts :fuvdrp:s: opt; do - case $opt in - f) failed=true && partest_args+=" --failed" ;; - p) cotouched="$cotouched $OPTARG" ;; - r) sortCommand="randomSort" ;; - s) since="$OPTARG" ;; - q) partest_args+=" --terse" ;; - u) partest_args+=" --update-check" ;; - v) partest_args+=" --verbose" ;; - :) echo "Option -$OPTARG requires an argument." >&2 ;; - *) ack_args+="-$OPTARG" ;; # don't drop unknown args, assume they're for ack - esac -done - -shift $((OPTIND-1)) -ack_args=( "${ack_args[@]}" "$@" ) - -# These methods all just create paths which may or may not be tests -# all are filtered through partest-paths which limits the output to actual tests -regexPathTests () { find "$filesdir" | ack --noenv "$@"; } -failedTests () { for p in $(find "$filesdir" -name '*.log'); do p1=${p%.log} && p2=${p1%-*} && echo "$p2"; done; } -sinceTests() { git log --since="$@" --name-only --pretty="format:" -- "$filesdir"; } -regexCodeTests () { ack $standard_ack_args "$@" -- "$filesdir"; } -sameCommitTests() { for rev in $(git rev-list HEAD -- "$@"); do git --no-pager show --pretty="format:" --name-only "$rev" -- "$filesdir"; done; } - -countStdout () { - local -i count=0 - while read line; do - printf "$line\n" && count+=1 - done - - printf >&2 " $count\n" -} - -randomSort () { - sort -u | while read line; do echo "$RANDOM $line"; done | sort | sed -E 's/^[0-9]+ //' -} - -testRun () { - local description="$1" && shift - printf >&2 "%% tests %-25s ... " "$description" - "$@" | "$partestPaths" | countStdout | egrep -v '^[ ]*$' -} - -allMatches() { - [[ -n $ack_args ]] && testRun "with matching paths" regexPathTests "${ack_args[@]}" - [[ -n $ack_args ]] && testRun "with matching code" regexCodeTests "${ack_args[@]}" - [[ -n $cotouched ]] && testRun "modified in same commit" sameCommitTests $cotouched - [[ -n $since ]] && testRun "modified since time" sinceTests "$since" - [[ -n $failed ]] && testRun "failed on last run" failedTests -} - -paths=$(allMatches | $sortCommand) - -[[ -z $paths ]] && [[ -z $failed ]] && echo >&2 "No matching tests." && exit 0; - -count=$(echo $(echo "$paths" | wc -w)) -[[ "$count" -eq 0 ]] && echo >&2 "No tests to run." && exit 0; - -# Output a command line which will re-run these same tests. -echo "# $count tests to run." -printf "%-52s %s\n" "$base/test/partest ${partest_args[*]}" "\\" -for path in $paths; do printf " %-50s %s\n" "$path" "\\"; done -echo "" - -test/partest ${partest_args[*]} $paths diff --git a/tools/partest-paths b/tools/partest-paths deleted file mode 100755 index 6ce403a04e..0000000000 --- a/tools/partest-paths +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh -# -# Given a list of files on stdin, translates them into a set -# of tests covering those files. That means paths which aren't -# part of a test are dropped and the rest are rewritten to the -# primary test path, with duplicates dropped. - -cd "$(dirname "$0")/.." - -# We have to enumerate good test dirs since partest chokes and fails -# on continuations, bench, etc. tests -pathRegex="test/files/(pos|neg|jvm|run|scalap|presentation)/[^/.]+([.]scala)?\$" - -# Echo the argument only if it matches our idea of a test and exists. -isPath () { [[ "$1" =~ $pathRegex ]] && [[ -e "$1" ]]; } - -# Filter stdin down to actual test paths. -asTestPaths() { - while read -r p; do - # Matched file at the standard test depth - p1="${p%.*}" && isPath "$p1.scala" && echo "$p1.scala" && continue - # Or, matched file may be in a test subdirectory, so strip the last path segment and check - p2="${p1%/*}" && isPath "$p2" && echo "$p2" && continue - done -} - -asTestPaths | sort -u diff --git a/versions.properties b/versions.properties index ae903bfe6e..f767dfab7b 100644 --- a/versions.properties +++ b/versions.properties @@ -16,12 +16,12 @@ scala.binary.version=2.12 # external modules shipped with distribution, as specified by scala-library-all's pom scala-xml.version.number=1.0.6 -scala-parser-combinators.version.number=1.0.4 -scala-swing.version.number=2.0.0-M2 -scala-swing.version.osgi=2.0.0.M2 +scala-parser-combinators.version.number=1.0.5 +scala-swing.version.number=2.0.0 +scala-swing.version.osgi=2.0.0 jline.version=2.14.3 # this one is shaded and embedded in scala-compiler.jar -scala-asm.version=5.1.0-scala-1 +scala-asm.version=5.1.0-scala-2 # external modules, used internally (not shipped) partest.version.number=1.1.0 |