-
Notifications
You must be signed in to change notification settings - Fork 360
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
The implementation of `java.lang.Number.__scala_==` was correct in spirit, but failed in practice because of quirks of the linker and `java.lang.Object.__scala_==`. Normally, `Object.__scala_==` should be implemented as `this.equals(that)`. For performance reasons, it is instead implemented as `this eq that`, with the understanding that the linker will patch the vtable of any class that overrides `equals` so that `__scala_==` refers to that `equals`. The issue is that this patching does not apply to super calls of the form `super.__scala_==`, making any such call incorrect. We fix the issue by directly calling `this.equals(that)` instead of `super.__scala_==`, since the former would be the reasonable implementation of `Object.__scala_==`.
- Loading branch information
1 parent
9bfd3fa
commit 83c86ef
Showing
4 changed files
with
312 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
253 changes: 253 additions & 0 deletions
253
unit-tests/src/test/scala/java/lang/ScalaNumberSuite.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,253 @@ | ||
package java.lang | ||
|
||
// Exercise __scala_== | ||
|
||
object ScalaNumberSuite extends tests.Suite { | ||
|
||
test("BigInt") { // Section header, visually group tests | ||
} | ||
|
||
test(" BigInt == BigInt") { | ||
val token = 2047L | ||
val sbi1: scala.math.BigInt = scala.math.BigInt(token) | ||
val sbi2: scala.math.BigInt = scala.math.BigInt(token) | ||
|
||
assert(sbi1 == sbi2) | ||
} | ||
|
||
test(" BigInt.equals(BigInt)") { | ||
val token = 2047L | ||
val sbi1: scala.math.BigInt = scala.math.BigInt(token) | ||
val sbi2: scala.math.BigInt = scala.math.BigInt(token) | ||
|
||
assert(sbi1.equals(sbi2)) | ||
} | ||
|
||
test(" BigInt does not == BigInt with different value") { | ||
val token = 2047L | ||
val sbi1: scala.math.BigInt = scala.math.BigInt(token) | ||
// avoid powers of 2 because of possible caching. | ||
val sbi2: scala.math.BigInt = scala.math.BigInt(token + 2) | ||
|
||
assertFalse(sbi1 == sbi2) | ||
} | ||
|
||
test(" BigInt == j.l.Long") { | ||
val token = Int.MaxValue + 2L | ||
val sbi: scala.math.BigInt = scala.math.BigInt(token) | ||
val jl: java.lang.Long = new java.lang.Long(token.toString) | ||
|
||
assert(sbi == jl) | ||
} | ||
|
||
test(" BigInt does not == j.l.Long with different value") { | ||
val token = Int.MaxValue + 2L | ||
val sbi: scala.math.BigInt = scala.math.BigInt(token) | ||
val jl: java.lang.Long = new java.lang.Long((token + 2).toString) | ||
|
||
assertFalse(sbi == jl) | ||
} | ||
|
||
test(" j.l.Long == BigInt") { | ||
val token = Int.MaxValue + 2L | ||
val sbi: scala.math.BigInt = scala.math.BigInt(token) | ||
val jl: java.lang.Long = new java.lang.Long(token.toString) | ||
|
||
assert(jl == sbi) | ||
} | ||
|
||
test(" j.l.Long does not == BigInt with different value") { | ||
val token = Int.MaxValue + 2L | ||
val sbi: scala.math.BigInt = scala.math.BigInt(token) | ||
val jl: java.lang.Long = new java.lang.Long((token + 2).toString) | ||
|
||
assertFalse(jl == sbi) | ||
} | ||
|
||
test(" j.l.Long == j.l.Long") { | ||
val token = 2047 | ||
val jl1: java.lang.Long = new java.lang.Long(token) | ||
val jl2: java.lang.Long = new java.lang.Long(token) | ||
|
||
assert(jl1 == jl2) | ||
} | ||
|
||
test(" j.l.Long does not == j.l.Long with different value") { | ||
val token = 2047 | ||
val jl1: java.lang.Long = new java.lang.Long(token) | ||
val jl2: java.lang.Long = new java.lang.Long(token + 2) | ||
|
||
assertFalse(jl1 == jl2) | ||
} | ||
|
||
test(" BigInt == j.l.Integer") { | ||
val token = 2047L | ||
val sbi: scala.math.BigInt = scala.math.BigInt(token) | ||
val ji: java.lang.Integer = new java.lang.Integer(token.toString) | ||
|
||
assert(sbi == ji) | ||
} | ||
|
||
test(" BigInt does not == j.l.Integer with different value") { | ||
val token = 2047L | ||
val sbi: scala.math.BigInt = scala.math.BigInt(token) | ||
val ji: java.lang.Integer = new java.lang.Integer((token + 2).toString) | ||
|
||
assertFalse(sbi == ji) | ||
} | ||
|
||
test(" j.l.Integer == BigInt") { | ||
val token = 2047L | ||
val sbi: scala.math.BigInt = scala.math.BigInt(token) | ||
val ji: java.lang.Integer = new java.lang.Integer(token.toString) | ||
|
||
assert(ji == sbi) | ||
} | ||
|
||
test(" j.l.Integer does not == BigInt with different value") { | ||
val token = 2047L | ||
val sbi: scala.math.BigInt = scala.math.BigInt(token) | ||
val ji: java.lang.Integer = new java.lang.Integer((token + 2).toString) | ||
|
||
assertFalse(ji == sbi) | ||
} | ||
|
||
test(" j.l.Integer == j.l.Integer") { | ||
val token = 2047 | ||
val ji1: java.lang.Integer = new java.lang.Integer(token) | ||
val ji2: java.lang.Integer = new java.lang.Integer(token) | ||
|
||
assert(ji1 == ji2) | ||
} | ||
|
||
test(" j.l.Integer does not == j.l.Integer with different value") { | ||
val token = 2047 | ||
val ji1: java.lang.Integer = new java.lang.Integer(token) | ||
val ji2: java.lang.Integer = new java.lang.Integer(token + 2) | ||
|
||
assertFalse(ji1 == ji2) | ||
} | ||
|
||
test("BigDecimal") { // Section header, visually group tests | ||
} | ||
|
||
test(" BigDecimal == BigDecimal") { | ||
val token = 2046.5 | ||
val sbd1: scala.math.BigDecimal = scala.math.BigDecimal(token) | ||
val sbd2: scala.math.BigDecimal = scala.math.BigDecimal(token) | ||
|
||
assert(sbd1 == sbd2) | ||
} | ||
|
||
test(" BigDecimal.equals(BigDecimal)") { | ||
val token = 2046.5 | ||
val sbd1: scala.math.BigDecimal = scala.math.BigDecimal(token) | ||
val sbd2: scala.math.BigDecimal = scala.math.BigDecimal(token) | ||
|
||
assert(sbd1.equals(sbd2)) | ||
} | ||
|
||
test(" BigDecimal does not == BigDecimal with different value") { | ||
val token = 2046.5 | ||
val sbd1: scala.math.BigDecimal = scala.math.BigDecimal(token) | ||
val sbd2: scala.math.BigDecimal = scala.math.BigDecimal(token - 2.0) | ||
|
||
assertFalse(sbd1 == sbd2) | ||
} | ||
|
||
test(" BigDecimal == j.l.Double") { | ||
val token = 2046.5 | ||
val sbd: scala.math.BigDecimal = scala.math.BigDecimal(token) | ||
val jd: java.lang.Double = new java.lang.Double(token.toString) | ||
|
||
assert(sbd == jd) | ||
} | ||
|
||
test(" BigDecimal does not == j.l.Double with different value") { | ||
val token = 2046.5 | ||
val sbd: scala.math.BigDecimal = scala.math.BigDecimal(token) | ||
val jd: java.lang.Double = new java.lang.Double((token - 2.0).toString) | ||
|
||
assertFalse(sbd == jd) | ||
} | ||
|
||
test(" j.l.Double == BigDecimal") { | ||
val token = 2046.5 | ||
val sbd: scala.math.BigDecimal = scala.math.BigDecimal(token) | ||
val jd: java.lang.Double = new java.lang.Double(token.toString) | ||
|
||
assert(jd == sbd) | ||
} | ||
|
||
test(" j.l.Double does not == BigDecimal with different value") { | ||
val token = 2046.5 | ||
val sbd: scala.math.BigDecimal = scala.math.BigDecimal(token) | ||
val jd: java.lang.Double = new java.lang.Double((token - 2.0).toString) | ||
|
||
assertFalse(sbd == jd) | ||
} | ||
|
||
test(" j.l.Double == j.l.Double") { | ||
val token = 2046.5 | ||
val jd1: java.lang.Double = new java.lang.Double(token) | ||
val jd2: java.lang.Double = new java.lang.Double(token) | ||
|
||
assert(jd1 == jd2) | ||
} | ||
|
||
test(" j.l.Double does not == j.l.Double with different value") { | ||
val token = 2046.5 | ||
val jd1: java.lang.Double = new java.lang.Double(token) | ||
val jd2: java.lang.Double = new java.lang.Double((token - 2.0).toString) | ||
|
||
assertFalse(jd1 == jd2) | ||
} | ||
|
||
test(" BigDecimal == j.l.Float") { | ||
val token = 2046.5F | ||
val sbd: scala.math.BigDecimal = scala.math.BigDecimal(token) | ||
val jf: java.lang.Float = new java.lang.Float(token.toString) | ||
|
||
assert(sbd == jf) | ||
} | ||
|
||
test(" BigDecimal does not == j.l.Float with different value") { | ||
val token = 2046.5F | ||
val sbd: scala.math.BigDecimal = scala.math.BigDecimal(token) | ||
val jf: java.lang.Float = new java.lang.Float((token - 2.0).toString) | ||
|
||
assertFalse(sbd == jf) | ||
} | ||
|
||
test(" j.l.Float == BigDecimal") { | ||
val token = 2046.5F | ||
val sbd: scala.math.BigDecimal = scala.math.BigDecimal(token) | ||
val jf: java.lang.Float = new java.lang.Float(token.toString) | ||
|
||
assert(jf == sbd) | ||
} | ||
|
||
test(" j.l.Float does not == BigDecimal with different value") { | ||
val token = 2046.5F | ||
val sbd: scala.math.BigDecimal = scala.math.BigDecimal(token) | ||
val jf: java.lang.Float = new java.lang.Float((token - 2.0).toString) | ||
|
||
assertFalse(jf == sbd) | ||
} | ||
|
||
test(" j.l.Float == j.l.Float") { | ||
val token = 2046.5F | ||
val jf1: java.lang.Float = new java.lang.Float(token) | ||
val jf2: java.lang.Float = new java.lang.Float(token) | ||
|
||
assert(jf1 == jf2) | ||
} | ||
|
||
test(" j.l.Float does not == j.l.Float with different value") { | ||
val token = 2046.5F | ||
val jf1: java.lang.Float = new java.lang.Float(token) | ||
val jf2: java.lang.Float = new java.lang.Float((token - 2.0).toString) | ||
|
||
assertFalse(jf1 == jf2) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package java.math | ||
|
||
object BigDecimalSuite extends tests.Suite { | ||
// __scala_== | ||
|
||
test("BigDecimal == BigDecimal") { | ||
val token = 2046.5 | ||
val jbd1: java.math.BigDecimal = java.math.BigDecimal.valueOf(token) | ||
val jbd2: java.math.BigDecimal = java.math.BigDecimal.valueOf(token) | ||
|
||
// Depending upon possible caching, they may or may not be eq. | ||
assert(jbd1 == jbd2) | ||
} | ||
|
||
test("BigDecimal.equals(BigDecimal)") { | ||
val token = 2046.5 | ||
val jbd1: java.math.BigDecimal = java.math.BigDecimal.valueOf(token) | ||
val jbd2: java.math.BigDecimal = java.math.BigDecimal.valueOf(token) | ||
|
||
// Depending upon possible caching, they may or may not be reference eq. | ||
assert(jbd1.equals(jbd2)) | ||
} | ||
|
||
test("BigDecimal does not == BigDecimal with different value") { | ||
val token = 2046.5 | ||
val jbd1: java.math.BigDecimal = java.math.BigDecimal.valueOf(token) | ||
val jbd2: java.math.BigDecimal = java.math.BigDecimal.valueOf(token + 1.0) | ||
|
||
assertFalse(jbd1 == jbd2) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters