summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2012-09-08 18:43:22 +0200
committerJason Zaugg <jzaugg@gmail.com>2012-09-08 18:52:51 +0200
commit815f60ff9c50d22a23fbc9d980570fb6941a7d71 (patch)
treea313adaf9493d35eecb858c1d6bcdba6e272979f
parentc619f94a9cfbddc12c9c5df3affb4636f8982a0a (diff)
downloadscala-815f60ff9c50d22a23fbc9d980570fb6941a7d71.tar.gz
scala-815f60ff9c50d22a23fbc9d980570fb6941a7d71.tar.bz2
scala-815f60ff9c50d22a23fbc9d980570fb6941a7d71.zip
Refine equality of Constant types over floating point values.
The constant types for 0d and -0d should not be equal. This is implemented by checking equality of the result of doubleToRawLongBits / floatToRawIntBits, which also correctly considers two NaNs of the same flavour to be equal. Followup to SI-6331.
-rw-r--r--src/reflect/scala/reflect/internal/Constants.scala12
-rw-r--r--test/files/run/t6331.check23
-rw-r--r--test/files/run/t6331.scala63
3 files changed, 96 insertions, 2 deletions
diff --git a/src/reflect/scala/reflect/internal/Constants.scala b/src/reflect/scala/reflect/internal/Constants.scala
index e5a543da46..4d512e3864 100644
--- a/src/reflect/scala/reflect/internal/Constants.scala
+++ b/src/reflect/scala/reflect/internal/Constants.scala
@@ -83,8 +83,16 @@ trait Constants extends api.Constants {
*/
override def equals(other: Any): Boolean = other match {
case that: Constant =>
- this.tag == that.tag &&
- (this.value == that.value || this.isNaN && that.isNaN)
+ // Consider two NaNs to be identical, despite non-equality
+ // Consider -0d to be distinct from 0d, despite equality
+ import java.lang.Double.doubleToRawLongBits
+ import java.lang.Float.floatToRawIntBits
+
+ this.tag == that.tag && ((value, that.value) match {
+ case (f1: Float, f2: Float) => floatToRawIntBits(f1) == floatToRawIntBits(f2)
+ case (d1: Double, d2: Double) => doubleToRawLongBits(d1) == doubleToRawLongBits(d2)
+ case (v1, v2) => v1 == v2
+ })
case _ => false
}
diff --git a/test/files/run/t6331.check b/test/files/run/t6331.check
new file mode 100644
index 0000000000..9bf3f7823a
--- /dev/null
+++ b/test/files/run/t6331.check
@@ -0,0 +1,23 @@
+ () == ()
+ true == true
+ true != false
+ false != true
+ 0.toByte == 0.toByte
+ 0.toByte != 1.toByte
+ 0.toShort == 0.toShort
+ 0.toShort != 1.toShort
+ 0 == 0
+ 0 != 1
+ 0L == 0L
+ 0L != 1L
+ 0.0f == 0.0f
+ 0.0f != -0.0f
+ -0.0f != 0.0f
+ NaNf == NaNf
+ 0.0d == 0.0d
+ 0.0d != -0.0d
+ -0.0d != 0.0d
+ NaNd == NaNd
+ 0 != 0.0d
+ 0 != 0L
+ 0.0d != 0.0f
diff --git a/test/files/run/t6331.scala b/test/files/run/t6331.scala
new file mode 100644
index 0000000000..e9ed96fad3
--- /dev/null
+++ b/test/files/run/t6331.scala
@@ -0,0 +1,63 @@
+import scala.tools.partest._
+import java.io._
+import scala.tools.nsc._
+import scala.tools.nsc.util.CommandLineParser
+import scala.tools.nsc.{Global, Settings, CompilerCommand}
+import scala.tools.nsc.reporters.ConsoleReporter
+
+// Test of Constant#equals, which must must account for floating point intricacies.
+object Test extends DirectTest {
+
+ override def code = ""
+
+ override def show() {
+ val global = newCompiler()
+ import global._
+
+ def check(c1: Any, c2: Any): Unit = {
+ val equal = Constant(c1) == Constant(c2)
+ def show(a: Any) = "" + a + (a match {
+ case _: Byte => ".toByte"
+ case _: Short => ".toShort"
+ case _: Long => "L"
+ case _: Float => "f"
+ case _: Double => "d"
+ case _ => ""
+ })
+ val op = if (equal) "==" else "!="
+ println(f"${show(c1)}%12s $op ${show(c2)}")
+ }
+
+ check((), ())
+
+ check(true, true)
+ check(true, false)
+ check(false, true)
+
+ check(0.toByte, 0.toByte)
+ check(0.toByte, 1.toByte)
+
+ check(0.toShort, 0.toShort)
+ check(0.toShort, 1.toShort)
+
+ check(0, 0)
+ check(0, 1)
+
+ check(0L, 0L)
+ check(0L, 1L)
+
+ check(0f, 0f)
+ check(0f, -0f)
+ check(-0f, 0f)
+ check(Float.NaN, Float.NaN)
+
+ check(0d, 0d)
+ check(0d, -0d)
+ check(-0d, 0d)
+ check(Double.NaN, Double.NaN)
+
+ check(0, 0d)
+ check(0, 0L)
+ check(0d, 0f)
+ }
+}