diff options
author | Adriaan Moors <adriaan@lightbend.com> | 2017-03-10 09:28:39 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-03-10 09:28:39 -0800 |
commit | 6e9268b08e813b6930165877fe6ce450890f0a9e (patch) | |
tree | d05b54711eb9782d8368b43c3a15aea9423ec183 | |
parent | 680d8661420a6ae4d0c1d9d46145d2b815255ef3 (diff) | |
parent | 6abb6ba47ad7a111385d1b4f5d2a90d81ee4472a (diff) | |
download | scala-6e9268b08e813b6930165877fe6ce450890f0a9e.tar.gz scala-6e9268b08e813b6930165877fe6ce450890f0a9e.tar.bz2 scala-6e9268b08e813b6930165877fe6ce450890f0a9e.zip |
Merge pull request #5761 from lrytz/sd329
Don't use `equals` for comparing java.lang.Double/Float
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala | 18 | ||||
-rw-r--r-- | test/files/run/number-parsing.scala | 4 | ||||
-rw-r--r-- | test/files/run/sd329.scala | 76 |
3 files changed, 91 insertions, 7 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index 76d042ce3b..37dea477c6 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -1264,14 +1264,22 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { def genEqEqPrimitive(l: Tree, r: Tree, success: asm.Label, failure: asm.Label, targetIfNoJump: asm.Label, pos: Position) { /* True if the equality comparison is between values that require the use of the rich equality - * comparator (scala.runtime.Comparator.equals). This is the case when either side of the + * comparator (scala.runtime.BoxesRunTime.equals). This is the case when either side of the * comparison might have a run-time type subtype of java.lang.Number or java.lang.Character. - * When it is statically known that both sides are equal and subtypes of Number of Character, - * not using the rich equality is possible (their own equals method will do ok.) + * + * When it is statically known that both sides are equal and subtypes of Number or Character, + * not using the rich equality is possible (their own equals method will do ok), except for + * java.lang.Float and java.lang.Double: their `equals` have different behavior around `NaN` + * and `-0.0`, see Javadoc (scala-dev#329). */ val mustUseAnyComparator: Boolean = { - val areSameFinals = l.tpe.isFinalType && r.tpe.isFinalType && (l.tpe =:= r.tpe) - !areSameFinals && platform.isMaybeBoxed(l.tpe.typeSymbol) && platform.isMaybeBoxed(r.tpe.typeSymbol) + platform.isMaybeBoxed(l.tpe.typeSymbol) && platform.isMaybeBoxed(r.tpe.typeSymbol) && { + val areSameFinals = l.tpe.isFinalType && r.tpe.isFinalType && (l.tpe =:= r.tpe) && { + val sym = l.tpe.typeSymbol + sym != BoxedFloatClass && sym != BoxedDoubleClass + } + !areSameFinals + } } if (mustUseAnyComparator) { diff --git a/test/files/run/number-parsing.scala b/test/files/run/number-parsing.scala index ad1481063e..5627ee9006 100644 --- a/test/files/run/number-parsing.scala +++ b/test/files/run/number-parsing.scala @@ -3,8 +3,8 @@ object Test { val MinusZero = Float.box(-0.0f) val PlusZero = Float.box(0.0f) - assert(PlusZero match { case MinusZero => false ; case _ => true }) - assert(MinusZero match { case PlusZero => false ; case _ => true }) + assert(PlusZero match { case MinusZero => true ; case _ => false }) + assert(MinusZero match { case PlusZero => true ; case _ => false }) assert((MinusZero: scala.Float) == (PlusZero: scala.Float)) assert(!(MinusZero equals PlusZero)) diff --git a/test/files/run/sd329.scala b/test/files/run/sd329.scala new file mode 100644 index 0000000000..c934e2c986 --- /dev/null +++ b/test/files/run/sd329.scala @@ -0,0 +1,76 @@ +object Test extends App { + def d1: Double = 0.0 + def d2: Double = -0.0 + def d3: Double = Double.NaN + def d4: Double = Double.NaN + assert(d1 == d2) + assert(d3 != d4) + + def d1B: java.lang.Double = d1 + def d2B: java.lang.Double = d2 + def d3B: java.lang.Double = d3 + def d4B: java.lang.Double = d4 + assert(d1B == d2B) + assert(d1 == d1B) + assert(d1B == d1) + assert(d3B != d4B) + assert(d3 != d4B) + assert(d3B != d4) + + assert(!d1B.equals(d2B)) // ! see javadoc + assert( d3B.equals(d4B)) // ! see javadoc + + def d1A: Any = d1 + def d2A: Any = d2 + def d3A: Any = d3 + def d4A: Any = d4 + assert(d1A == d2A) + assert(d1 == d1A) + assert(d1A == d1) + assert(d1B == d1A) + assert(d1A == d1B) + + assert(d3A != d4A) + assert(d3 != d4A) + assert(d3A != d4) + assert(d3B != d4A) + assert(d3A != d4B) + + + def f1: Float = 0.0f + def f2: Float = -0.0f + def f3: Float = Float.NaN + def f4: Float = Float.NaN + assert(f1 == f2) + assert(f3 != f4) + + def f1B: java.lang.Float = f1 + def f2B: java.lang.Float = f2 + def f3B: java.lang.Float = f3 + def f4B: java.lang.Float = f4 + assert(f1B == f2B) + assert(f1 == f1B) + assert(f1B == f1) + assert(f3B != f4B) + assert(f3 != f4B) + assert(f3B != f4) + + assert(!f1B.equals(f2B)) // ! see javadoc + assert( f3B.equals(f4B)) // ! see javadoc + + def f1A: Any = f1 + def f2A: Any = f2 + def f3A: Any = f3 + def f4A: Any = f4 + assert(f1A == f2A) + assert(f1 == f1A) + assert(f1A == f1) + assert(f1B == f1A) + assert(f1A == f1B) + + assert(f3A != f4A) + assert(f3 != f4A) + assert(f3A != f4) + assert(f3B != f4A) + assert(f3A != f4B) +} |