summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala13
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala24
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala3
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/CopyProp.scala14
-rw-r--r--src/intellij/README.md2
-rw-r--r--src/library/scala/Predef.scala2
-rw-r--r--src/library/scala/collection/immutable/Queue.scala8
-rw-r--r--src/library/scala/math/package.scala253
-rw-r--r--src/library/scala/util/Either.scala312
-rw-r--r--test/files/presentation/doc/doc.scala6
-rw-r--r--test/files/presentation/t7678/Runner.scala2
-rw-r--r--test/files/run/t3326.scala2
-rw-r--r--test/files/scalacheck/CheckEither.scala70
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala20
15 files changed, 534 insertions, 199 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala b/src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala
index 4ad4a95728..7b640ac54f 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala
@@ -26,9 +26,7 @@ final class BackendReportingImpl(val global: Global) extends BackendReporting {
/**
* Utilities for error reporting.
*
- * Defines some tools to make error reporting with Either easier. Would be subsumed by a right-biased
- * Either in the standard library (or scalaz \/) (Validation is different, it accumulates multiple
- * errors).
+ * Defines some utility methods to make error reporting with Either easier.
*/
object BackendReporting {
def methodSignature(classInternalName: InternalName, name: String, desc: String) = {
@@ -42,19 +40,12 @@ object BackendReporting {
def assertionError(message: String): Nothing = throw new AssertionError(message)
implicit class RightBiasedEither[A, B](val v: Either[A, B]) extends AnyVal {
- def map[C](f: B => C): Either[A, C] = v.right.map(f)
- def flatMap[C](f: B => Either[A, C]): Either[A, C] = v.right.flatMap(f)
def withFilter(f: B => Boolean)(implicit empty: A): Either[A, B] = v match {
case Left(_) => v
case Right(e) => if (f(e)) v else Left(empty) // scalaz.\/ requires an implicit Monoid m to get m.empty
}
- def foreach[U](f: B => U): Unit = v.right.foreach(f)
- def getOrElse[C >: B](alt: => C): C = v.right.getOrElse(alt)
-
- /**
- * Get the value, fail with an assertion if this is an error.
- */
+ /** Get the value, fail with an assertion if this is an error. */
def get: B = {
assert(v.isRight, v.left.get)
v.right.get
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
index 1feca56923..d65380aa1f 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
@@ -217,26 +217,6 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
nonOverloadedConstructors(tupleClassSymbols)
}
- // enumeration of specialized classes is temporary, while we still use the java-defined JFunctionN.
- // once we switch to ordinary FunctionN, we can use specializedSubclasses just like for tuples.
- private def specializedJFunctionSymbols(base: String): Seq[Symbol] = {
- def primitives = Seq("B", "S", "I", "J", "C", "F", "D", "Z", "V")
- def ijfd = Iterator("I", "J", "F", "D")
- def ijfdzv = Iterator("I", "J", "F", "D", "Z", "V")
- def ijd = Iterator("I", "J", "D")
- val classNames = {
- primitives.map(base + "0$mc" + _ + "$sp") // Function0
- } ++ {
- // return type specializations appear first in the name string (alphabetical sorting)
- for (r <- ijfdzv; a <- ijfd) yield base + "1$mc" + r + a + "$sp" // Function1
- } ++ {
- for (r <- ijfdzv; a <- ijd; b <- ijd) yield base + "2$mc" + r + a + b + "$sp" // Function2
- }
- classNames map getRequiredClass
- }
-
- lazy val functionRefs: Set[InternalName] = (FunctionClass.seq ++ specializedJFunctionSymbols("scala.runtime.java8.JFunction")).map(classBTypeFromSymbol(_).internalName).toSet
-
lazy val typeOfArrayOp: Map[Int, BType] = {
import scalaPrimitives._
Map(
@@ -342,8 +322,6 @@ trait CoreBTypesProxyGlobalIndependent[BTS <: BTypes] {
def srRefConstructors : Map[InternalName, MethodNameAndType]
def tupleClassConstructors : Map[InternalName, MethodNameAndType]
- def functionRefs: Set[InternalName]
-
def lambdaMetaFactoryBootstrapHandle : asm.Handle
def lambdaDeserializeBootstrapHandle : asm.Handle
}
@@ -410,8 +388,6 @@ final class CoreBTypesProxy[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes:
def srRefConstructors : Map[InternalName, MethodNameAndType] = _coreBTypes.srRefConstructors
def tupleClassConstructors : Map[InternalName, MethodNameAndType] = _coreBTypes.tupleClassConstructors
- def functionRefs: Set[InternalName] = _coreBTypes.functionRefs
-
def srSymbolLiteral : ClassBType = _coreBTypes.srSymbolLiteral
def srStructuralCallSite : ClassBType = _coreBTypes.srStructuralCallSite
def srLambdaDeserialize : ClassBType = _coreBTypes.srLambdaDeserialize
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 539435a326..83615abc31 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala
@@ -131,7 +131,6 @@ class BackendUtils[BT <: BTypes](val btypes: BT) {
private val anonfunAdaptedName = """.*\$anonfun\$.*\$\d+\$adapted""".r
def hasAdaptedImplMethod(closureInit: ClosureInstantiation): Boolean = {
- isBuiltinFunctionType(Type.getReturnType(closureInit.lambdaMetaFactoryCall.indy.desc).getInternalName) &&
anonfunAdaptedName.pattern.matcher(closureInit.lambdaMetaFactoryCall.implMethod.getName).matches
}
@@ -256,8 +255,6 @@ class BackendUtils[BT <: BTypes](val btypes: BT) {
}
}
- def isBuiltinFunctionType(internalName: InternalName): Boolean = functionRefs(internalName)
-
/**
* Visit the class node and collect all referenced nested classes.
*/
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 d6942d9ff9..5248183337 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
@@ -430,7 +430,7 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
def unapply(insn: AbstractInsnNode): Option[(InvokeDynamicInsnNode, Type, Handle, Type)] = insn match {
case indy: InvokeDynamicInsnNode if indy.bsm == metafactoryHandle || indy.bsm == altMetafactoryHandle =>
indy.bsmArgs match {
- case Array(samMethodType: Type, implMethod: Handle, instantiatedMethodType: Type, xs@_*) => // xs binding because IntelliJ gets confused about _@_*
+ case Array(samMethodType: Type, implMethod: Handle, instantiatedMethodType: Type, _@_*) =>
// LambdaMetaFactory performs a number of automatic adaptations when invoking the lambda
// implementation method (casting, boxing, unboxing, and primitive widening, see Javadoc).
//
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 4163d62df7..b05669ce89 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/CopyProp.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/CopyProp.scala
@@ -295,18 +295,12 @@ class CopyProp[BT <: BTypes](val btypes: BT) {
}
/**
- * Eliminate the closure value produced by `indy`. If the SAM type is known to construct
- * without side-effects (e.g. scala/FunctionN), the `indy` and its inputs
- * are eliminated, otherwise a POP is inserted.
+ * Eliminate LMF `indy` and its inputs.
*/
def handleClosureInst(indy: InvokeDynamicInsnNode): Unit = {
- if (isBuiltinFunctionType(Type.getReturnType(indy.desc).getInternalName)) {
- toRemove += indy
- callGraph.removeClosureInstantiation(indy, method)
- handleInputs(indy, Type.getArgumentTypes(indy.desc).length)
- } else {
- toInsertAfter(indy) = getPop(1)
- }
+ toRemove += indy
+ callGraph.removeClosureInstantiation(indy, method)
+ handleInputs(indy, Type.getArgumentTypes(indy.desc).length)
}
def runQueue(): Unit = while (queue.nonEmpty) {
diff --git a/src/intellij/README.md b/src/intellij/README.md
index 41fef04183..650d91e5d1 100644
--- a/src/intellij/README.md
+++ b/src/intellij/README.md
@@ -60,7 +60,7 @@ breakpoints within the Scala compiler.
## Running the Compiler and REPL
You can create run/debug configurations to run the compiler and REPL directly within
-IntelliJ, which might accelerate development and debugging of the the compiler.
+IntelliJ, which might accelerate development and debugging of the compiler.
To debug the Scala codebase you can also use "Remote" debug configuration and pass
the corresponding arguments to the jvm running the compiler / program.
diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala
index 5f1a6b0bbb..8de9754b50 100644
--- a/src/library/scala/Predef.scala
+++ b/src/library/scala/Predef.scala
@@ -71,7 +71,7 @@ import scala.io.StdIn
*
* @groupname assertions Assertions
* @groupprio assertions 20
- * @groupdesc assertions These methods support program verfication and runtime correctness.
+ * @groupdesc assertions These methods support program verification and runtime correctness.
*
* @groupname console-output Console Output
* @groupprio console-output 30
diff --git a/src/library/scala/collection/immutable/Queue.scala b/src/library/scala/collection/immutable/Queue.scala
index 3ad6656636..1dd0d7683a 100644
--- a/src/library/scala/collection/immutable/Queue.scala
+++ b/src/library/scala/collection/immutable/Queue.scala
@@ -84,6 +84,14 @@ sealed class Queue[+A] protected(protected val in: List[A], protected val out: L
else if (in.nonEmpty) new Queue(Nil, in.reverse.tail)
else throw new NoSuchElementException("tail on empty queue")
+ /* This is made to avoid inefficient implementation of iterator. */
+ override def forall(p: A => Boolean): Boolean =
+ in.forall(p) && out.forall(p)
+
+ /* This is made to avoid inefficient implementation of iterator. */
+ override def exists(p: A => Boolean): Boolean =
+ in.exists(p) || out.exists(p)
+
/** Returns the length of the queue.
*/
override def length = in.length + out.length
diff --git a/src/library/scala/math/package.scala b/src/library/scala/math/package.scala
index 0e39af2feb..546efef114 100644
--- a/src/library/scala/math/package.scala
+++ b/src/library/scala/math/package.scala
@@ -11,28 +11,90 @@ package scala
/** The package object `scala.math` contains methods for performing basic
* numeric operations such as elementary exponential, logarithmic, root and
* trigonometric functions.
+ *
+ * All methods forward to [[java.lang.Math]] unless otherwise noted.
+ *
+ * @see [[java.lang.Math]]
+ *
+ * @groupname math-const Mathematical Constants
+ * @groupprio math-const 10
+ *
+ * @groupname minmax Minimum and Maximum
+ * @groupdesc minmax Find the min or max of two numbers. Note: [[scala.collection.TraversableOnce]] has
+ * min and max methods which determine the min or max of a collection.
+ * @groupprio minmax 20
+ *
+ * @groupname rounding Rounding
+ * @groupprio rounding 30
+ *
+ * @groupname explog Exponential and Logarithmic
+ * @groupprio explog 40
+ *
+ * @groupname trig Trigonometric
+ * @groupdesc trig Arguments in radians
+ * @groupprio trig 50
+ *
+ * @groupname angle-conversion Angular Measurement Conversion
+ * @groupprio angle-conversion 60
+ *
+ * @groupname hyperbolic Hyperbolic
+ * @groupprio hyperbolic 70
+ *
+ * @groupname abs Absolute Values
+ * @groupdesc abs Determine the magnitude of a value by discarding the sign. Results are >= 0.
+ * @groupprio abs 80
+ *
+ * @groupname signum Signs
+ * @groupdesc signum Extract the sign of a value. Results are -1, 0 or 1.
+ * Note that these are not pure forwarders to the java versions.
+ * In particular, the return type of java.lang.Long.signum is Int,
+ * but here it is widened to Long so that each overloaded variant
+ * will return the same numeric type it is passed.
+ * @groupprio signum 90
+ *
+ * @groupname root-extraction Root Extraction
+ * @groupprio root-extraction 100
+ *
+ * @groupname polar-coords Polar Coordinates
+ * @groupprio polar-coords 110
+ *
+ * @groupname ulp Unit of Least Precision
+ * @groupprio ulp 120
+ *
+ * @groupname randomisation Pseudo Random Number Generation
+ * @groupprio randomisation 130
*/
package object math {
- /** The `double` value that is closer than any other to `e`, the base of
+ /** The `Double` value that is closer than any other to `e`, the base of
* the natural logarithms.
+ * @group math-const
*/
@inline final val E = java.lang.Math.E
- /** The `double` value that is closer than any other to `pi`, the ratio of
+ /** The `Double` value that is closer than any other to `pi`, the ratio of
* the circumference of a circle to its diameter.
+ * @group math-const
*/
@inline final val Pi = java.lang.Math.PI
- /** Returns a `double` value with a positive sign, greater than or equal
+ /** Returns a `Double` value with a positive sign, greater than or equal
* to `0.0` and less than `1.0`.
+ *
+ * @group randomisation
*/
def random(): Double = java.lang.Math.random()
+ /** @group trig */
def sin(x: Double): Double = java.lang.Math.sin(x)
+ /** @group trig */
def cos(x: Double): Double = java.lang.Math.cos(x)
+ /** @group trig */
def tan(x: Double): Double = java.lang.Math.tan(x)
+ /** @group trig */
def asin(x: Double): Double = java.lang.Math.asin(x)
+ /** @group trig */
def acos(x: Double): Double = java.lang.Math.acos(x)
+ /** @group trig */
def atan(x: Double): Double = java.lang.Math.atan(x)
/** Converts an angle measured in degrees to an approximately equivalent
@@ -40,6 +102,7 @@ package object math {
*
* @param x an angle, in degrees
* @return the measurement of the angle `x` in radians.
+ * @group angle-conversion
*/
def toRadians(x: Double): Double = java.lang.Math.toRadians(x)
@@ -48,44 +111,10 @@ package object math {
*
* @param x angle, in radians
* @return the measurement of the angle `x` in degrees.
+ * @group angle-conversion
*/
def toDegrees(x: Double): Double = java.lang.Math.toDegrees(x)
- /** Returns Euler's number `e` raised to the power of a `double` value.
- *
- * @param x the exponent to raise `e` to.
- * @return the value `e^a^`, where `e` is the base of the natural
- * logarithms.
- */
- def exp(x: Double): Double = java.lang.Math.exp(x)
-
- /** Returns the natural logarithm of a `double` value.
- *
- * @param x the number to take the natural logarithm of
- * @return the value `logₑ(x)` where `e` is Eulers number
- */
- def log(x: Double): Double = java.lang.Math.log(x)
-
- /** Returns the square root of a `double` value.
- *
- * @param x the number to take the square root of
- * @return the value √x
- */
- def sqrt(x: Double): Double = java.lang.Math.sqrt(x)
- def IEEEremainder(x: Double, y: Double): Double = java.lang.Math.IEEEremainder(x, y)
-
- def ceil(x: Double): Double = java.lang.Math.ceil(x)
- def floor(x: Double): Double = java.lang.Math.floor(x)
-
- /** Returns the `double` value that is closest in value to the
- * argument and is equal to a mathematical integer.
- *
- * @param x a `double` value
- * @return the closest floating-point value to a that is equal to a
- * mathematical integer.
- */
- def rint(x: Double): Double = java.lang.Math.rint(x)
-
/** Converts rectangular coordinates `(x, y)` to polar `(r, theta)`.
*
* @param x the ordinate coordinate
@@ -93,19 +122,44 @@ package object math {
* @return the ''theta'' component of the point `(r, theta)` in polar
* coordinates that corresponds to the point `(x, y)` in
* Cartesian coordinates.
+ * @group polar-coords
*/
def atan2(y: Double, x: Double): Double = java.lang.Math.atan2(y, x)
- /** Returns the value of the first argument raised to the power of the
- * second argument.
+ /** Returns the square root of the sum of the squares of both given `Double`
+ * values without intermediate underflow or overflow.
+ *
+ * The ''r'' component of the point `(r, theta)` in polar
+ * coordinates that corresponds to the point `(x, y)` in
+ * Cartesian coordinates.
+ * @group polar-coords
+ */
+ def hypot(x: Double, y: Double): Double = java.lang.Math.hypot(x, y)
+
+ // -----------------------------------------------------------------------
+ // rounding functions
+ // -----------------------------------------------------------------------
+
+ /** @group rounding */
+ def ceil(x: Double): Double = java.lang.Math.ceil(x)
+ /** @group rounding */
+ def floor(x: Double): Double = java.lang.Math.floor(x)
+
+ /** Returns the `Double` value that is closest in value to the
+ * argument and is equal to a mathematical integer.
+ *
+ * @param x a `Double` value
+ * @return the closest floating-point value to a that is equal to a
+ * mathematical integer.
+ * @group rounding
+ */
+ def rint(x: Double): Double = java.lang.Math.rint(x)
+
+ /** There is no reason to round a `Long`, but this method prevents unintended conversion to `Float` followed by rounding to `Int`.
*
- * @param x the base.
- * @param y the exponent.
- * @return the value `x^y^`.
+ * @note Does not forward to [[java.lang.Math]]
+ * @group rounding
*/
- def pow(x: Double, y: Double): Double = java.lang.Math.pow(x, y)
-
- /** There is no reason to round a `Long`, but this method prevents unintended conversion to `Float` followed by rounding to `Int`. */
@deprecated("This is an integer type; there is no reason to round it. Perhaps you meant to call this with a floating-point value?", "2.11.0")
def round(x: Long): Long = x
@@ -113,6 +167,7 @@ package object math {
*
* @param x a floating-point value to be rounded to a `Int`.
* @return the value of the argument rounded to the nearest `Int` value.
+ * @group rounding
*/
def round(x: Float): Int = java.lang.Math.round(x)
@@ -120,83 +175,153 @@ package object math {
*
* @param x a floating-point value to be rounded to a `Long`.
* @return the value of the argument rounded to the nearest`long` value.
+ * @group rounding
*/
def round(x: Double): Long = java.lang.Math.round(x)
+ /** @group abs */
def abs(x: Int): Int = java.lang.Math.abs(x)
+ /** @group abs */
def abs(x: Long): Long = java.lang.Math.abs(x)
+ /** @group abs */
def abs(x: Float): Float = java.lang.Math.abs(x)
+ /** @group abs */
def abs(x: Double): Double = java.lang.Math.abs(x)
+ /** @group minmax */
def max(x: Int, y: Int): Int = java.lang.Math.max(x, y)
+ /** @group minmax */
def max(x: Long, y: Long): Long = java.lang.Math.max(x, y)
+ /** @group minmax */
def max(x: Float, y: Float): Float = java.lang.Math.max(x, y)
+ /** @group minmax */
def max(x: Double, y: Double): Double = java.lang.Math.max(x, y)
+ /** @group minmax */
def min(x: Int, y: Int): Int = java.lang.Math.min(x, y)
+ /** @group minmax */
def min(x: Long, y: Long): Long = java.lang.Math.min(x, y)
+ /** @group minmax */
def min(x: Float, y: Float): Float = java.lang.Math.min(x, y)
+ /** @group minmax */
def min(x: Double, y: Double): Double = java.lang.Math.min(x, y)
- /** Note that these are not pure forwarders to the java versions.
- * In particular, the return type of java.lang.Long.signum is Int,
- * but here it is widened to Long so that each overloaded variant
- * will return the same numeric type it is passed.
- */
+ /** @group signum
+ * @note Forwards to [[java.lang.Integer]]
+ */
def signum(x: Int): Int = java.lang.Integer.signum(x)
+ /** @group signum
+ * @note Forwards to [[java.lang.Long]]
+ */
def signum(x: Long): Long = java.lang.Long.signum(x)
+ /** @group signum */
def signum(x: Float): Float = java.lang.Math.signum(x)
+ /** @group signum */
def signum(x: Double): Double = java.lang.Math.signum(x)
// -----------------------------------------------------------------------
// root functions
// -----------------------------------------------------------------------
- /** Returns the cube root of the given `Double` value. */
+ /** Returns the square root of a `Double` value.
+ *
+ * @param x the number to take the square root of
+ * @return the value √x
+ * @group root-extraction
+ */
+ def sqrt(x: Double): Double = java.lang.Math.sqrt(x)
+
+ /** Returns the cube root of the given `Double` value.
+ *
+ * @param x the number to take the cube root of
+ * @return the value ∛x
+ * @group root-extraction
+ */
def cbrt(x: Double): Double = java.lang.Math.cbrt(x)
// -----------------------------------------------------------------------
// exponential functions
// -----------------------------------------------------------------------
- /** Returns `exp(x) - 1`. */
+ /** Returns the value of the first argument raised to the power of the
+ * second argument.
+ *
+ * @param x the base.
+ * @param y the exponent.
+ * @return the value `x^y^`.
+ * @group explog
+ */
+ def pow(x: Double, y: Double): Double = java.lang.Math.pow(x, y)
+
+ /** Returns Euler's number `e` raised to the power of a `Double` value.
+ *
+ * @param x the exponent to raise `e` to.
+ * @return the value `e^a^`, where `e` is the base of the natural
+ * logarithms.
+ * @group explog
+ */
+ def exp(x: Double): Double = java.lang.Math.exp(x)
+
+ /** Returns `exp(x) - 1`.
+ * @group explog
+ */
def expm1(x: Double): Double = java.lang.Math.expm1(x)
// -----------------------------------------------------------------------
// logarithmic functions
// -----------------------------------------------------------------------
- /** Returns the natural logarithm of the sum of the given `Double` value and 1. */
+ /** Returns the natural logarithm of a `Double` value.
+ *
+ * @param x the number to take the natural logarithm of
+ * @return the value `logₑ(x)` where `e` is Eulers number
+ * @group explog
+ */
+ def log(x: Double): Double = java.lang.Math.log(x)
+
+ /** Returns the natural logarithm of the sum of the given `Double` value and 1.
+ * @group explog
+ */
def log1p(x: Double): Double = java.lang.Math.log1p(x)
- /** Returns the base 10 logarithm of the given `Double` value. */
+ /** Returns the base 10 logarithm of the given `Double` value.
+ * @group explog
+ */
def log10(x: Double): Double = java.lang.Math.log10(x)
// -----------------------------------------------------------------------
// trigonometric functions
// -----------------------------------------------------------------------
- /** Returns the hyperbolic sine of the given `Double` value. */
+ /** Returns the hyperbolic sine of the given `Double` value.
+ * @group hyperbolic
+ */
def sinh(x: Double): Double = java.lang.Math.sinh(x)
- /** Returns the hyperbolic cosine of the given `Double` value. */
+ /** Returns the hyperbolic cosine of the given `Double` value.
+ * @group hyperbolic
+ */
def cosh(x: Double): Double = java.lang.Math.cosh(x)
- /** Returns the hyperbolic tangent of the given `Double` value. */
+ /** Returns the hyperbolic tangent of the given `Double` value.
+ * @group hyperbolic
+ */
def tanh(x: Double):Double = java.lang.Math.tanh(x)
// -----------------------------------------------------------------------
// miscellaneous functions
// -----------------------------------------------------------------------
- /** Returns the square root of the sum of the squares of both given `Double`
- * values without intermediate underflow or overflow.
+ /** Returns the size of an ulp of the given `Double` value.
+ * @group ulp
*/
- def hypot(x: Double, y: Double): Double = java.lang.Math.hypot(x, y)
-
- /** Returns the size of an ulp of the given `Double` value. */
def ulp(x: Double): Double = java.lang.Math.ulp(x)
- /** Returns the size of an ulp of the given `Float` value. */
+ /** Returns the size of an ulp of the given `Float` value.
+ * @group ulp
+ */
def ulp(x: Float): Float = java.lang.Math.ulp(x)
+
+ /** @group rounding */
+ def IEEEremainder(x: Double, y: Double): Double = java.lang.Math.IEEEremainder(x, y)
}
diff --git a/src/library/scala/util/Either.scala b/src/library/scala/util/Either.scala
index 01da0c1ef2..5c61d83a1a 100644
--- a/src/library/scala/util/Either.scala
+++ b/src/library/scala/util/Either.scala
@@ -32,12 +32,21 @@ package util
* Left(in)
* }
*
- * println( result match {
- * case Right(x) => "You passed me the Int: " + x + ", which I will increment. " + x + " + 1 = " + (x+1)
- * case Left(x) => "You passed me the String: " + x
+ * println(result match {
+ * case Right(x) => s"You passed me the Int: $x, which I will increment. $x + 1 = ${x+1}"
+ * case Left(x) => s"You passed me the String: $x"
* })
* }}}
*
+ * Either is right-biased, which means that Right is assumed to be the default case to
+ * operate on. If it is Left, operations like map, flatMap, ... return the Left value
+ * unchanged:
+ *
+ * {{{
+ * Right(12).map(_ * 2) // Right(24)
+ * Left(23).map(_ * 2) // Left(23)
+ * }}}
+ *
* A ''projection'' can be used to selectively operate on a value of type Either,
* depending on whether it is of type Left or Right. For example, to transform an
* Either using a function, in the case where it's a Left, one can first apply
@@ -70,11 +79,13 @@ sealed abstract class Either[+A, +B] extends Product with Serializable {
/**
* Projects this `Either` as a `Left`.
*/
+ @deprecated("use swap instead", "2.12.0")
def left = Either.LeftProjection(this)
/**
* Projects this `Either` as a `Right`.
*/
+ @deprecated("Either is now right-biased", "2.12.0")
def right = Either.RightProjection(this)
/**
@@ -83,8 +94,8 @@ sealed abstract class Either[+A, +B] extends Product with Serializable {
* @example {{{
* val result: Either[Exception, Value] = possiblyFailingOperation()
* log(result.fold(
- * ex => "Operation failed with " + ex,
- * v => "Operation produced value: " + v
+ * ex => s"Operation failed with $ex",
+ * v => s"Operation produced value: $v"
* ))
* }}}
*
@@ -92,9 +103,9 @@ sealed abstract class Either[+A, +B] extends Product with Serializable {
* @param fb the function to apply if this is a `Right`
* @return the results of applying the function
*/
- def fold[X](fa: A => X, fb: B => X) = this match {
- case Left(a) => fa(a)
+ def fold[C](fa: A => C, fb: B => C): C = this match {
case Right(b) => fb(b)
+ case Left(a) => fa(a)
}
/**
@@ -105,8 +116,8 @@ sealed abstract class Either[+A, +B] extends Product with Serializable {
* val r: Either[Int, String] = l.swap // Result: Right("left")
* }}}
*/
- def swap = this match {
- case Left(a) => Right(a)
+ def swap: Either[B, A] = this match {
+ case Left(a) => Right(a)
case Right(b) => Left(b)
}
@@ -130,8 +141,9 @@ sealed abstract class Either[+A, +B] extends Product with Serializable {
* This method, and `joinLeft`, are analogous to `Option#flatten`
*/
def joinRight[A1 >: A, B1 >: B, C](implicit ev: B1 <:< Either[A1, C]): Either[A1, C] = this match {
- case Left(a) => Left(a)
case Right(b) => b
+ case Left(a) => this.asInstanceOf[Either[A1, C]]
+
}
/**
@@ -155,7 +167,155 @@ sealed abstract class Either[+A, +B] extends Product with Serializable {
*/
def joinLeft[A1 >: A, B1 >: B, C](implicit ev: A1 <:< Either[C, B1]): Either[C, B1] = this match {
case Left(a) => a
- case Right(b) => Right(b)
+ case Right(b) => this.asInstanceOf[Either[C, B1]]
+ }
+
+ /**
+ * Executes the given side-effecting function if this is a `Right`.
+ *
+ * {{{
+ * Right(12).foreach(x => println(x)) // prints "12"
+ * Left(12).foreach(x => println(x)) // doesn't print
+ * }}}
+ * @param f The side-effecting function to execute.
+ */
+ def foreach[U](f: B => U): Unit = this match {
+ case Right(b) => f(b)
+ case Left(_) =>
+ }
+
+ /**
+ * Returns the value from this `Right` or the given argument if this is a `Left`.
+ *
+ * {{{
+ * Right(12).getOrElse(17) // 12
+ * Left(12).getOrElse(17) // 17
+ * }}}
+ */
+ def getOrElse[BB >: B](or: => BB): BB = this match {
+ case Right(b) => b
+ case Left(_) => or
+ }
+
+ /** Returns `true` if this is a `Right` and its value is equal to `elem` (as determined by `==`),
+ * returns `false` otherwise.
+ *
+ * {{{
+ * // Returns true because value of Right is "something" which equals "something".
+ * Right("something") contains "something"
+ *
+ * // Returns false because value of Right is "something" which does not equal "anything".
+ * Right("something") contains "anything"
+ *
+ * // Returns false because there is no value for Right.
+ * Left("something") contains "something"
+ * }}}
+ *
+ * @param elem the element to test.
+ * @return `true` if the option has an element that is equal (as determined by `==`) to `elem`, `false` otherwise.
+ */
+ final def contains[BB >: B](elem: BB): Boolean = this match {
+ case Right(b) => b == elem
+ case Left(_) => false
+ }
+
+ /**
+ * Returns `true` if `Left` or returns the result of the application of
+ * the given function to the `Right` value.
+ *
+ * {{{
+ * Right(12).forall(_ > 10) // true
+ * Right(7).forall(_ > 10) // false
+ * Left(12).forall(_ > 10) // true
+ * }}}
+ */
+ def forall(f: B => Boolean): Boolean = this match {
+ case Right(b) => f(b)
+ case Left(_) => true
+ }
+
+ /**
+ * Returns `false` if `Left` or returns the result of the application of
+ * the given function to the `Right` value.
+ *
+ * {{{
+ * Right(12).exists(_ > 10) // true
+ * Right(7).exists(_ > 10) // false
+ * Left(12).exists(_ > 10) // false
+ * }}}
+ */
+ def exists(p: B => Boolean): Boolean = this match {
+ case Right(b) => p(b)
+ case Left(_) => false
+ }
+
+ /**
+ * Binds the given function across `Right`.
+ *
+ * @param f The function to bind across `Right`.
+ */
+ def flatMap[AA >: A, Y](f: B => Either[AA, Y]): Either[AA, Y] = this match {
+ case Right(b) => f(b)
+ case Left(a) => this.asInstanceOf[Either[AA, Y]]
+ }
+
+ /**
+ * The given function is applied if this is a `Right`.
+ *
+ * {{{
+ * Right(12).map(x => "flower") // Result: Right("flower")
+ * Left(12).map(x => "flower") // Result: Left(12)
+ * }}}
+ */
+ def map[Y](f: B => Y): Either[A, Y] = this match {
+ case Right(b) => Right(f(b))
+ case Left(a) => this.asInstanceOf[Either[A, Y]]
+ }
+
+ /** Returns `Right` with the existing value of `Right` if this is a `Right` and the given predicate `p` holds for the right value,
+ * returns `Left(zero)` if this is a `Right` and the given predicate `p` does not hold for the right value,
+ * returns `Left` with the existing value of `Left` if this is a `Left`.
+ *
+ * {{{
+ * Right(12).filterOrElse(_ > 10, -1) // Right(12)
+ * Right(7).filterOrElse(_ > 10, -1) // Left(-1)
+ * Left(12).filterOrElse(_ > 10, -1) // Left(12)
+ * }}}
+ */
+ def filterOrElse[AA >: A](p: B => Boolean, zero: => AA): Either[AA, B] = this match {
+ case Right(b) => if (p(b)) this else Left(zero)
+ case Left(a) => this
+ }
+
+ /** Returns a `Seq` containing the `Right` value if
+ * it exists or an empty `Seq` if this is a `Left`.
+ *
+ * {{{
+ * Right(12).toSeq // Seq(12)
+ * Left(12).toSeq // Seq()
+ * }}}
+ */
+ def toSeq: collection.immutable.Seq[B] = this match {
+ case Right(b) => collection.immutable.Seq(b)
+ case Left(_) => collection.immutable.Seq.empty
+ }
+
+ /** Returns a `Some` containing the `Right` value
+ * if it exists or a `None` if this is a `Left`.
+ *
+ * {{{
+ * Right(12).toOption // Some(12)
+ * Left(12).toOption // None
+ * }}}
+ */
+ def toOption: Option[B] = this match {
+ case Right(b) => Some(b)
+ case Left(_) => None
+ }
+
+ def toTry(implicit ev: A <:< Throwable): Try[B] = this match {
+ case Right(b) => Success(b)
+ case Left(a) => Failure(a)
}
/**
@@ -186,7 +346,7 @@ sealed abstract class Either[+A, +B] extends Product with Serializable {
* @version 1.0, 11/10/2008
*/
final case class Left[+A, +B](a: A) extends Either[A, B] {
- def isLeft = true
+ def isLeft = true
def isRight = false
}
@@ -197,12 +357,26 @@ final case class Left[+A, +B](a: A) extends Either[A, B] {
* @version 1.0, 11/10/2008
*/
final case class Right[+A, +B](b: B) extends Either[A, B] {
- def isLeft = false
+ def isLeft = false
def isRight = true
}
object Either {
+ /** If the condition is satisfied, return the given `B` in `Right`,
+ * otherwise, return the given `A` in `Left`.
+ *
+ * {{{
+ * val userInput: String = ...
+ * Either.cond(
+ * userInput.forall(_.isDigit) && userInput.size == 10,
+ * PhoneNumber(userInput),
+ * "The input (%s) does not look like a phone number".format(userInput)
+ * }}}
+ */
+ def cond[X, Y](test: Boolean, right: => Y, left: => X): Either[X, Y] =
+ if (test) Right(right) else Left(left)
+
/**
* Allows use of a `merge` method to extract values from Either instances
* regardless of whether they are Left or Right.
@@ -216,8 +390,8 @@ object Either {
*/
implicit class MergeableEither[A](private val x: Either[A, A]) extends AnyVal {
def merge: A = x match {
- case Left(a) => a
case Right(a) => a
+ case Left(a) => a
}
}
@@ -250,7 +424,7 @@ object Either {
* }}}
*
* {{{
- * // using Either
+ * // using Either
* def interactWithDB(x: Query): Either[Exception, Result] =
* try {
* Right(getResultFromDatabase(x))
@@ -270,6 +444,7 @@ object Either {
* @author <a href="mailto:research@workingmouse.com">Tony Morris</a>, Workingmouse
* @version 1.0, 11/10/2008
*/
+ @deprecated("use swap instead", "2.12.0")
final case class LeftProjection[+A, +B](e: Either[A, B]) {
/**
* Returns the value from this `Left` or throws `java.util.NoSuchElementException`
@@ -282,9 +457,9 @@ object Either {
*
* @throws java.util.NoSuchElementException if the projection is [[scala.util.Right]]
*/
- def get = e match {
- case Left(a) => a
- case Right(_) => throw new NoSuchElementException("Either.left.value on Right")
+ def get: A = e match {
+ case Left(a) => a
+ case Right(_) => throw new NoSuchElementException("Either.left.get on Right")
}
/**
@@ -296,14 +471,13 @@ object Either {
* }}}
* @param f The side-effecting function to execute.
*/
- def foreach[U](f: A => U) = e match {
- case Left(a) => f(a)
- case Right(_) => {}
+ def foreach[U](f: A => U): Unit = e match {
+ case Left(a) => f(a)
+ case Right(_) =>
}
/**
- * Returns the value from this `Left` or the given argument if this is a
- * `Right`.
+ * Returns the value from this `Left` or the given argument if this is a `Right`.
*
* {{{
* Left(12).left.getOrElse(17) // 12
@@ -311,8 +485,8 @@ object Either {
* }}}
*
*/
- def getOrElse[AA >: A](or: => AA) = e match {
- case Left(a) => a
+ def getOrElse[AA >: A](or: => AA): AA = e match {
+ case Left(a) => a
case Right(_) => or
}
@@ -327,8 +501,8 @@ object Either {
* }}}
*
*/
- def forall(@deprecatedName('f) p: A => Boolean) = e match {
- case Left(a) => p(a)
+ def forall(@deprecatedName('f) p: A => Boolean): Boolean = e match {
+ case Left(a) => p(a)
case Right(_) => true
}
@@ -343,8 +517,8 @@ object Either {
* }}}
*
*/
- def exists(@deprecatedName('f) p: A => Boolean) = e match {
- case Left(a) => p(a)
+ def exists(@deprecatedName('f) p: A => Boolean): Boolean = e match {
+ case Left(a) => p(a)
case Right(_) => false
}
@@ -357,9 +531,9 @@ object Either {
* }}}
* @param f The function to bind across `Left`.
*/
- def flatMap[BB >: B, X](f: A => Either[X, BB]) = e match {
- case Left(a) => f(a)
- case Right(b) => Right(b)
+ def flatMap[BB >: B, X](f: A => Either[X, BB]): Either[X, BB] = e match {
+ case Left(a) => f(a)
+ case Right(b) => e.asInstanceOf[Either[X, BB]]
}
/**
@@ -370,9 +544,9 @@ object Either {
* Right[Int, Int](12).left.map(_ + 2) // Right(12)
* }}}
*/
- def map[X](f: A => X) = e match {
- case Left(a) => Left(f(a))
- case Right(b) => Right(b)
+ def map[X](f: A => X): Either[X, B] = e match {
+ case Left(a) => Left(f(a))
+ case Right(b) => e.asInstanceOf[Either[X, B]]
}
/**
@@ -386,7 +560,7 @@ object Either {
* }}}
*/
def filter[Y](p: A => Boolean): Option[Either[A, Y]] = e match {
- case Left(a) => if(p(a)) Some(Left(a)) else None
+ case Left(a) => if(p(a)) Some(Left(a)) else None
case Right(b) => None
}
@@ -399,8 +573,8 @@ object Either {
* Right(12).left.toSeq // Seq()
* }}}
*/
- def toSeq = e match {
- case Left(a) => Seq(a)
+ def toSeq: Seq[A] = e match {
+ case Left(a) => Seq(a)
case Right(_) => Seq.empty
}
@@ -413,8 +587,8 @@ object Either {
* Right(12).left.toOption // None
* }}}
*/
- def toOption = e match {
- case Left(a) => Some(a)
+ def toOption: Option[A] = e match {
+ case Left(a) => Some(a)
case Right(_) => None
}
}
@@ -434,6 +608,7 @@ object Either {
* @author <a href="mailto:research@workingmouse.com">Tony Morris</a>, Workingmouse
* @version 1.0, 11/10/2008
*/
+ @deprecated("Either is now right-biased", "2.12.0")
final case class RightProjection[+A, +B](e: Either[A, B]) {
/**
@@ -447,9 +622,9 @@ object Either {
*
* @throws java.util.NoSuchElementException if the projection is `Left`.
*/
- def get = e match {
- case Left(_) => throw new NoSuchElementException("Either.right.value on Left")
- case Right(a) => a
+ def get: B = e match {
+ case Right(b) => b
+ case Left(_) => throw new NoSuchElementException("Either.right.get on Left")
}
/**
@@ -461,23 +636,22 @@ object Either {
* }}}
* @param f The side-effecting function to execute.
*/
- def foreach[U](f: B => U) = e match {
- case Left(_) => {}
+ def foreach[U](f: B => U): Unit = e match {
case Right(b) => f(b)
+ case Left(_) =>
}
/**
- * Returns the value from this `Right` or the given argument if this is a
- * `Left`.
+ * Returns the value from this `Right` or the given argument if this is a `Left`.
*
* {{{
* Right(12).right.getOrElse(17) // 12
* Left(12).right.getOrElse(17) // 17
* }}}
*/
- def getOrElse[BB >: B](or: => BB) = e match {
- case Left(_) => or
+ def getOrElse[BB >: B](or: => BB): BB = e match {
case Right(b) => b
+ case Left(_) => or
}
/**
@@ -490,9 +664,9 @@ object Either {
* Left(12).right.forall(_ > 10) // true
* }}}
*/
- def forall(f: B => Boolean) = e match {
- case Left(_) => true
+ def forall(f: B => Boolean): Boolean = e match {
case Right(b) => f(b)
+ case Left(_) => true
}
/**
@@ -505,9 +679,9 @@ object Either {
* Left(12).right.exists(_ > 10) // false
* }}}
*/
- def exists(@deprecatedName('f) p: B => Boolean) = e match {
- case Left(_) => false
+ def exists(@deprecatedName('f) p: B => Boolean): Boolean = e match {
case Right(b) => p(b)
+ case Left(_) => false
}
/**
@@ -515,9 +689,9 @@ object Either {
*
* @param f The function to bind across `Right`.
*/
- def flatMap[AA >: A, Y](f: B => Either[AA, Y]) = e match {
- case Left(a) => Left(a)
+ def flatMap[AA >: A, Y](f: B => Either[AA, Y]): Either[AA, Y] = e match {
case Right(b) => f(b)
+ case Left(a) => e.asInstanceOf[Either[AA, Y]]
}
/**
@@ -528,9 +702,9 @@ object Either {
* Left(12).right.map(x => "flower") // Result: Left(12)
* }}}
*/
- def map[Y](f: B => Y) = e match {
- case Left(a) => Left(a)
+ def map[Y](f: B => Y): Either[A, Y] = e match {
case Right(b) => Right(f(b))
+ case Left(a) => e.asInstanceOf[Either[A, Y]]
}
/** Returns `None` if this is a `Left` or if the
@@ -544,8 +718,8 @@ object Either {
* }}}
*/
def filter[X](p: B => Boolean): Option[Either[X, B]] = e match {
- case Left(_) => None
case Right(b) => if(p(b)) Some(Right(b)) else None
+ case Left(_) => None
}
/** Returns a `Seq` containing the `Right` value if
@@ -556,9 +730,9 @@ object Either {
* Left(12).right.toSeq // Seq()
* }}}
*/
- def toSeq = e match {
- case Left(_) => Seq.empty
+ def toSeq: Seq[B] = e match {
case Right(b) => Seq(b)
+ case Left(_) => Seq.empty
}
/** Returns a `Some` containing the `Right` value
@@ -569,23 +743,9 @@ object Either {
* Left(12).right.toOption // None
* }}}
*/
- def toOption = e match {
- case Left(_) => None
+ def toOption: Option[B] = e match {
case Right(b) => Some(b)
+ case Left(_) => None
}
}
-
- /** If the condition is satisfied, return the given `B` in `Right`,
- * otherwise, return the given `A` in `Left`.
- *
- * {{{
- * val userInput: String = ...
- * Either.cond(
- * userInput.forall(_.isDigit) && userInput.size == 10,
- * PhoneNumber(userInput),
- * "The input (%s) does not look like a phone number".format(userInput)
- * }}}
- */
- def cond[A, B](test: Boolean, right: => B, left: => A): Either[A, B] =
- if (test) Right(right) else Left(left)
}
diff --git a/test/files/presentation/doc/doc.scala b/test/files/presentation/doc/doc.scala
index ce431910ee..8c60af557b 100644
--- a/test/files/presentation/doc/doc.scala
+++ b/test/files/presentation/doc/doc.scala
@@ -62,7 +62,7 @@ object Test extends InteractiveTest {
def getComment(sym: Symbol, source: SourceFile, fragments: List[(Symbol,SourceFile)]): Option[Comment] = {
val docResponse = new Response[(String, String, Position)]
askDocComment(sym, source, sym.owner, fragments, docResponse)
- docResponse.get.left.toOption flatMap {
+ docResponse.get.swap.toOption flatMap {
case (expanded, raw, pos) =>
if (expanded.isEmpty)
None
@@ -85,13 +85,13 @@ object Test extends InteractiveTest {
val batch = new BatchSourceFile(source.file, newText.toCharArray)
val reloadResponse = new Response[Unit]
compiler.askReload(List(batch), reloadResponse)
- reloadResponse.get.left.toOption match {
+ reloadResponse.get.swap.toOption match {
case None =>
println("Couldn't reload")
case Some(_) =>
val parseResponse = new Response[Tree]
askParsedEntered(batch, true, parseResponse)
- parseResponse.get.left.toOption match {
+ parseResponse.get.swap.toOption match {
case None =>
println("Couldn't parse")
case Some(_) =>
diff --git a/test/files/presentation/t7678/Runner.scala b/test/files/presentation/t7678/Runner.scala
index 14d6dc2a70..c6736a65b0 100644
--- a/test/files/presentation/t7678/Runner.scala
+++ b/test/files/presentation/t7678/Runner.scala
@@ -7,7 +7,7 @@ object Test extends InteractiveTest {
override def runDefaultTests() {
def resolveTypeTagHyperlink() {
- val sym = compiler.askForResponse(() => compiler.currentRun.runDefinitions.TypeTagClass).get.left.get
+ val sym = compiler.askForResponse(() => compiler.currentRun.runDefinitions.TypeTagClass).get.swap.getOrElse(???)
val r = new Response[Position]
compiler.askLinkPos(sym, new BatchSourceFile("", source), r)
r.get
diff --git a/test/files/run/t3326.scala b/test/files/run/t3326.scala
index 4ac7ef9138..b6b4eac784 100644
--- a/test/files/run/t3326.scala
+++ b/test/files/run/t3326.scala
@@ -19,7 +19,7 @@ import scala.math.Ordering
* This is why `collection.SortedMap` used to resort to the generic
* `TraversableLike.++` which knows nothing about the ordering.
*
- * To avoid `collection.SortedMap`s resort to the more generic `TraverableLike.++`,
+ * To avoid `collection.SortedMap`s resort to the more generic `TraversableLike.++`,
* we override the `MapLike.++` overload in `collection.SortedMap` to return
* the proper type `SortedMap`.
*/
diff --git a/test/files/scalacheck/CheckEither.scala b/test/files/scalacheck/CheckEither.scala
index 48f732a22d..f0ec797045 100644
--- a/test/files/scalacheck/CheckEither.scala
+++ b/test/files/scalacheck/CheckEither.scala
@@ -132,6 +132,58 @@ object Test extends Properties("Either") {
case Right(a) => a
}))
+ val prop_getOrElse = forAll((e: Either[Int, Int], or: Int) => e.getOrElse(or) == (e match {
+ case Left(_) => or
+ case Right(b) => b
+ }))
+
+ val prop_contains = forAll((e: Either[Int, Int], n: Int) =>
+ e.contains(n) == (e.isRight && e.right.get == n))
+
+ val prop_forall = forAll((e: Either[Int, Int]) =>
+ e.forall(_ % 2 == 0) == (e.isLeft || e.right.get % 2 == 0))
+
+ val prop_exists = forAll((e: Either[Int, Int]) =>
+ e.exists(_ % 2 == 0) == (e.isRight && e.right.get % 2 == 0))
+
+ val prop_flatMapLeftIdentity = forAll((e: Either[Int, Int], n: Int, s: String) => {
+ def f(x: Int) = if(x % 2 == 0) Left(s) else Right(s)
+ Right(n).flatMap(f(_)) == f(n)})
+
+ val prop_flatMapRightIdentity = forAll((e: Either[Int, Int]) => e.flatMap(Right(_)) == e)
+
+ val prop_flatMapComposition = forAll((e: Either[Int, Int]) => {
+ def f(x: Int) = if(x % 2 == 0) Left(x) else Right(x)
+ def g(x: Int) = if(x % 7 == 0) Right(x) else Left(x)
+ e.flatMap(f(_)).flatMap(g(_)) == e.flatMap(f(_).flatMap(g(_)))})
+
+ val prop_mapIdentity = forAll((e: Either[Int, Int]) => e.map(x => x) == e)
+
+ val prop_mapComposition = forAll((e: Either[Int, String]) => {
+ def f(s: String) = s.toLowerCase
+ def g(s: String) = s.reverse
+ e.map(x => f(g(x))) == e.map(x => g(x)).map(f(_))})
+
+ val prop_filterOrElse = forAll((e: Either[Int, Int], x: Int) => e.filterOrElse(_ % 2 == 0, -x) ==
+ (if(e.isLeft) e
+ else if(e.right.get % 2 == 0) e
+ else Left(-x)))
+
+ val prop_seq = forAll((e: Either[Int, Int]) => e.toSeq == (e match {
+ case Left(_) => collection.immutable.Seq.empty
+ case Right(b) => collection.immutable.Seq(b)
+ }))
+
+ val prop_option = forAll((e: Either[Int, Int]) => e.toOption == (e match {
+ case Left(_) => None
+ case Right(b) => Some(b)
+ }))
+
+ val prop_try = forAll((e: Either[Throwable, Int]) => e.toTry == (e match {
+ case Left(a) => util.Failure(a)
+ case Right(b) => util.Success(b)
+ }))
+
/** Hard to believe I'm "fixing" a test to reflect B before A ... */
val prop_Either_cond = forAll((c: Boolean, a: Int, b: Int) =>
Either.cond(c, a, b) == (if(c) Right(a) else Left(b)))
@@ -169,9 +221,21 @@ object Test extends Properties("Either") {
("prop_Either_right", prop_Either_right),
("prop_Either_joinLeft", prop_Either_joinLeft),
("prop_Either_joinRight", prop_Either_joinRight),
- ("prop_Either_reduce", prop_Either_reduce),
- ("prop_Either_cond", prop_Either_cond)
- )
+ ("prop_Either_reduce", prop_Either_reduce),
+ ("prop_getOrElse", prop_getOrElse),
+ ("prop_contains", prop_contains),
+ ("prop_forall", prop_forall),
+ ("prop_exists", prop_exists),
+ ("prop_flatMapLeftIdentity", prop_flatMapLeftIdentity),
+ ("prop_flatMapRightIdentity", prop_flatMapRightIdentity),
+ ("prop_flatMapComposition", prop_flatMapComposition),
+ ("prop_mapIdentity", prop_mapIdentity),
+ ("prop_mapComposition", prop_mapComposition),
+ ("prop_filterOrElse", prop_filterOrElse),
+ ("prop_seq", prop_seq),
+ ("prop_option", prop_option),
+ ("prop_try", prop_try),
+ ("prop_Either_cond", prop_Either_cond))
for ((label, prop) <- tests) {
property(label) = prop
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala
index 938bc7b846..2c697bfe50 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala
@@ -750,4 +750,24 @@ class MethodLevelOptsTest extends BytecodeTesting {
-1, LDC, ASTORE,
-1, ALOAD, ARETURN))
}
+
+ @Test
+ def elimSamLambda(): Unit = {
+ val code =
+ """class C {
+ | def t1(x: Int) = {
+ | val fun: java.util.function.IntFunction[Int] = y => y + 1
+ | fun(x)
+ | }
+ | def t2(x: Int) = {
+ | val fun: T = i => i + 1
+ | fun.f(x)
+ | }
+ |}
+ |trait T { def f(x: Int): Int }
+ """.stripMargin
+ val List(c, t) = compileClasses(code)
+ assertSameSummary(getMethod(c, "t1"), List(ILOAD, "$anonfun$t1$1", IRETURN))
+ assertSameSummary(getMethod(c, "t2"), List(ILOAD, "$anonfun$t2$1", IRETURN))
+ }
}