Skip to content

Commit 4a8edc0

Browse files
retronymadriaanm
authored andcommitted
SI-8129 Make Object#== override Any#==
And the same for != If we tried to declare these signatures in non-fictional classes, we would be chastised about collapsing into the "same signature after erasure". This will have an influence of typing, as the typechecking of arguments is sensitive to overloading: if multiple variants are feasible, the argument will be typechecked with a wildcard expected type. So people inspecting the types of the arguments to `==` before this change might have seen an interesting type for `if (true) x else y`, but now the `If` will have type `Any`, as we don't need to calculate the LUB. I've left a TODO to note that we should really make `Any#{==, !=}` non-final and include a final override in `AnyVal`. But I don't think that is particularly urgent.
1 parent b0f81ed commit 4a8edc0

16 files changed

+71
-60
lines changed

src/library-aux/scala/AnyRef.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ trait AnyRef extends Any {
7676
* @param arg0 the object to compare against this object for equality.
7777
* @return `true` if the receiver object is equivalent to the argument; `false` otherwise.
7878
*/
79-
final def ==(that: AnyRef): Boolean =
80-
if (this eq null) that eq null
79+
final def ==(that: Any): Boolean =
80+
if (this eq null) that.asInstanceOf[AnyRef] eq null
8181
else this equals that
8282

8383
/** Create a copy of the receiver object.

src/reflect/scala/reflect/internal/Definitions.scala

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ trait Definitions extends api.StandardDefinitions {
3535
private def newMethod(owner: Symbol, name: TermName, formals: List[Type], restpe: Type, flags: Long): MethodSymbol = {
3636
val msym = owner.newMethod(name.encode, NoPosition, flags)
3737
val params = msym.newSyntheticValueParams(formals)
38-
msym setInfo MethodType(params, restpe) markAllCompleted
38+
val info = if (owner.isJavaDefined) JavaMethodType(params, restpe) else MethodType(params, restpe)
39+
msym setInfo info markAllCompleted
3940
}
4041
private def enterNewMethod(owner: Symbol, name: TermName, formals: List[Type], restpe: Type, flags: Long = 0L): MethodSymbol =
4142
owner.info.decls enter newMethod(owner, name, formals, restpe, flags)
@@ -904,8 +905,14 @@ trait Definitions extends api.StandardDefinitions {
904905
existentialAbstraction(clazz.unsafeTypeParams, clazz.tpe_*)
905906

906907
// members of class scala.Any
908+
909+
// TODO these aren't final! They are now overriden in AnyRef/Object. Prior to the fix
910+
// for SI-8129, they were actually *overloaded* by the members in AnyRef/Object.
911+
// We should unfinalize these, override in AnyValClass, and make the overrides final.
912+
// Refchecks never actually looks at these, so its just for consistency.
907913
lazy val Any_== = enterNewMethod(AnyClass, nme.EQ, AnyTpe :: Nil, BooleanTpe, FINAL)
908914
lazy val Any_!= = enterNewMethod(AnyClass, nme.NE, AnyTpe :: Nil, BooleanTpe, FINAL)
915+
909916
lazy val Any_equals = enterNewMethod(AnyClass, nme.equals_, AnyTpe :: Nil, BooleanTpe)
910917
lazy val Any_hashCode = enterNewMethod(AnyClass, nme.hashCode_, Nil, IntTpe)
911918
lazy val Any_toString = enterNewMethod(AnyClass, nme.toString_, Nil, StringTpe)
@@ -1012,8 +1019,8 @@ trait Definitions extends api.StandardDefinitions {
10121019

10131020
// members of class java.lang.{ Object, String }
10141021
lazy val Object_## = enterNewMethod(ObjectClass, nme.HASHHASH, Nil, IntTpe, FINAL)
1015-
lazy val Object_== = enterNewMethod(ObjectClass, nme.EQ, AnyRefTpe :: Nil, BooleanTpe, FINAL)
1016-
lazy val Object_!= = enterNewMethod(ObjectClass, nme.NE, AnyRefTpe :: Nil, BooleanTpe, FINAL)
1022+
lazy val Object_== = enterNewMethod(ObjectClass, nme.EQ, AnyTpe :: Nil, BooleanTpe, FINAL)
1023+
lazy val Object_!= = enterNewMethod(ObjectClass, nme.NE, AnyTpe :: Nil, BooleanTpe, FINAL)
10171024
lazy val Object_eq = enterNewMethod(ObjectClass, nme.eq, AnyRefTpe :: Nil, BooleanTpe, FINAL)
10181025
lazy val Object_ne = enterNewMethod(ObjectClass, nme.ne, AnyRefTpe :: Nil, BooleanTpe, FINAL)
10191026
lazy val Object_isInstanceOf = newT1NoParamsMethod(ObjectClass, nme.isInstanceOf_Ob, FINAL | SYNTHETIC | ARTIFACT)(_ => BooleanTpe)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
t8219-any-any-ref-equals.scala:5: error: method ==: (x$1: Any)Boolean does not take type parameters.
2+
"".==[Int]
3+
^
4+
t8219-any-any-ref-equals.scala:6: error: method ==: (x$1: Any)Boolean does not take type parameters.
5+
("": AnyRef).==[Int]
6+
^
7+
t8219-any-any-ref-equals.scala:7: error: method ==: (x$1: Any)Boolean does not take type parameters.
8+
("": Object).==[Int]
9+
^
10+
three errors found

test/pending/neg/t8219-any-any-ref-equals.scala renamed to test/files/neg/t8219-any-any-ref-equals.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@ object Test {
33
// A real class couldn't define such an overload, why do we allow AnyRef
44
// to do so?
55
"".==[Int]
6+
("": AnyRef).==[Int]
7+
("": Object).==[Int]
68
}

test/files/pos/t8219.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
trait Equalizer[T]
2+
trait Gen[A]
3+
4+
class Broken {
5+
implicit def const[T](x: T): Gen[T] = ???
6+
implicit def convertToEqualizer[T](left: T): Equalizer[T] = ???
7+
8+
def in(a: Any) = ()
9+
in {
10+
import scala.None // any import will do..
11+
"" == "" // this no longer triggers the bug, as Object#== now overrides Any#==
12+
}
13+
14+
// We can still trigger the bug with a structural type, see pending/neg/t8219.scala
15+
}

test/files/presentation/callcc-interpreter.check

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ reload: CallccInterpreter.scala
33
askTypeCompletion at CallccInterpreter.scala(51,34)
44
================================================================================
55
[response] askTypeCompletion at (51,34)
6-
retrieved 59 members
6+
retrieved 57 members
77
abstract trait Term extends AnyRef
88
abstract trait Value extends AnyRef
99
case class Add extends callccInterpreter.Term with Product with Serializable
@@ -38,10 +38,8 @@ def toString(): String
3838
def unitM[A](a: A): callccInterpreter.M[A]
3939
def →[B](y: B): (callccInterpreter.type, B)
4040
final def !=(x$1: Any): Boolean
41-
final def !=(x$1: AnyRef): Boolean
4241
final def ##(): Int
4342
final def ==(x$1: Any): Boolean
44-
final def ==(x$1: AnyRef): Boolean
4543
final def asInstanceOf[T0]: T0
4644
final def eq(x$1: AnyRef): Boolean
4745
final def isInstanceOf[T0]: Boolean

test/files/presentation/completion-implicit-chained.check

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,16 @@ reload: Completions.scala
33
askTypeCompletion at Completions.scala(11,16)
44
================================================================================
55
[response] askTypeCompletion at (11,16)
6-
retrieved 24 members
6+
retrieved 22 members
77
[inaccessible] protected[package lang] def clone(): Object
88
[inaccessible] protected[package lang] def finalize(): Unit
99
def equals(x$1: Any): Boolean
1010
def hashCode(): Int
1111
def map(x: Int => Int)(implicit a: DummyImplicit): test.O.type
1212
def toString(): String
1313
final def !=(x$1: Any): Boolean
14-
final def !=(x$1: AnyRef): Boolean
1514
final def ##(): Int
1615
final def ==(x$1: Any): Boolean
17-
final def ==(x$1: AnyRef): Boolean
1816
final def asInstanceOf[T0]: T0
1917
final def eq(x$1: AnyRef): Boolean
2018
final def isInstanceOf[T0]: Boolean

test/files/presentation/ide-bug-1000349.check

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ reload: CompletionOnEmptyArgMethod.scala
33
askTypeCompletion at CompletionOnEmptyArgMethod.scala(2,17)
44
================================================================================
55
[response] askTypeCompletion at (2,17)
6-
retrieved 32 members
6+
retrieved 30 members
77
def +(other: String): String
88
def ->[B](y: B): (Foo, B)
99
def ensuring(cond: Boolean): Foo
@@ -17,10 +17,8 @@ def hashCode(): Int
1717
def toString(): String
1818
def →[B](y: B): (Foo, B)
1919
final def !=(x$1: Any): Boolean
20-
final def !=(x$1: AnyRef): Boolean
2120
final def ##(): Int
2221
final def ==(x$1: Any): Boolean
23-
final def ==(x$1: AnyRef): Boolean
2422
final def asInstanceOf[T0]: T0
2523
final def eq(x$1: AnyRef): Boolean
2624
final def isInstanceOf[T0]: Boolean

test/files/presentation/ide-bug-1000475.check

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ reload: Foo.scala
33
askTypeCompletion at Foo.scala(3,7)
44
================================================================================
55
[response] askTypeCompletion at (3,7)
6-
retrieved 31 members
6+
retrieved 29 members
77
[inaccessible] protected[package lang] def clone(): Object
88
[inaccessible] protected[package lang] def finalize(): Unit
99
def +(other: String): String
@@ -18,10 +18,8 @@ def hashCode(): Int
1818
def toString(): String
1919
def →[B](y: B): (Object, B)
2020
final def !=(x$1: Any): Boolean
21-
final def !=(x$1: AnyRef): Boolean
2221
final def ##(): Int
2322
final def ==(x$1: Any): Boolean
24-
final def ==(x$1: AnyRef): Boolean
2523
final def asInstanceOf[T0]: T0
2624
final def eq(x$1: AnyRef): Boolean
2725
final def isInstanceOf[T0]: Boolean
@@ -37,7 +35,7 @@ final def wait(x$1: Long,x$2: Int): Unit
3735
askTypeCompletion at Foo.scala(6,10)
3836
================================================================================
3937
[response] askTypeCompletion at (6,10)
40-
retrieved 31 members
38+
retrieved 29 members
4139
[inaccessible] protected[package lang] def clone(): Object
4240
[inaccessible] protected[package lang] def finalize(): Unit
4341
def +(other: String): String
@@ -52,10 +50,8 @@ def hashCode(): Int
5250
def toString(): String
5351
def →[B](y: B): (Object, B)
5452
final def !=(x$1: Any): Boolean
55-
final def !=(x$1: AnyRef): Boolean
5653
final def ##(): Int
5754
final def ==(x$1: Any): Boolean
58-
final def ==(x$1: AnyRef): Boolean
5955
final def asInstanceOf[T0]: T0
6056
final def eq(x$1: AnyRef): Boolean
6157
final def isInstanceOf[T0]: Boolean
@@ -71,7 +67,7 @@ final def wait(x$1: Long,x$2: Int): Unit
7167
askTypeCompletion at Foo.scala(7,7)
7268
================================================================================
7369
[response] askTypeCompletion at (7,7)
74-
retrieved 31 members
70+
retrieved 29 members
7571
[inaccessible] protected[package lang] def clone(): Object
7672
[inaccessible] protected[package lang] def finalize(): Unit
7773
def +(other: String): String
@@ -86,10 +82,8 @@ def hashCode(): Int
8682
def toString(): String
8783
def →[B](y: B): (Object, B)
8884
final def !=(x$1: Any): Boolean
89-
final def !=(x$1: AnyRef): Boolean
9085
final def ##(): Int
9186
final def ==(x$1: Any): Boolean
92-
final def ==(x$1: AnyRef): Boolean
9387
final def asInstanceOf[T0]: T0
9488
final def eq(x$1: AnyRef): Boolean
9589
final def isInstanceOf[T0]: Boolean

test/files/presentation/ide-bug-1000531.check

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ reload: CrashOnLoad.scala
33
askTypeCompletion at CrashOnLoad.scala(6,12)
44
================================================================================
55
[response] askTypeCompletion at (6,12)
6-
retrieved 120 members
6+
retrieved 118 members
77
[inaccessible] protected[package lang] def clone(): Object
88
[inaccessible] protected[package lang] def finalize(): Unit
99
[inaccessible] protected[this] def reversed: List[B]
@@ -107,10 +107,8 @@ def zipWithIndex: Iterator[(B, Int)]
107107
def zip[B](that: Iterator[B]): Iterator[(B, B)]
108108
def →[B](y: B): (java.util.Iterator[B], B)
109109
final def !=(x$1: Any): Boolean
110-
final def !=(x$1: AnyRef): Boolean
111110
final def ##(): Int
112111
final def ==(x$1: Any): Boolean
113-
final def ==(x$1: AnyRef): Boolean
114112
final def asInstanceOf[T0]: T0
115113
final def eq(x$1: AnyRef): Boolean
116114
final def isInstanceOf[T0]: Boolean

test/files/presentation/implicit-member.check

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ reload: ImplicitMember.scala
33
askTypeCompletion at ImplicitMember.scala(7,7)
44
================================================================================
55
[response] askTypeCompletion at (7,7)
6-
retrieved 34 members
6+
retrieved 32 members
77
def +(other: String): String
88
def ->[B](y: B): (Implicit.type, B)
99
def ensuring(cond: Boolean): Implicit.type
@@ -17,10 +17,8 @@ def toString(): String
1717
def →[B](y: B): (Implicit.type, B)
1818
final class AppliedImplicit[A] extends AnyRef
1919
final def !=(x$1: Any): Boolean
20-
final def !=(x$1: AnyRef): Boolean
2120
final def ##(): Int
2221
final def ==(x$1: Any): Boolean
23-
final def ==(x$1: AnyRef): Boolean
2422
final def asInstanceOf[T0]: T0
2523
final def eq(x$1: AnyRef): Boolean
2624
final def isInstanceOf[T0]: Boolean

test/files/presentation/ping-pong.check

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ reload: PingPong.scala
33
askTypeCompletion at PingPong.scala(10,23)
44
================================================================================
55
[response] askTypeCompletion at (10,23)
6-
retrieved 35 members
6+
retrieved 33 members
77
[inaccessible] private[this] val ping: Ping
88
[inaccessible] protected[package lang] def clone(): Object
99
[inaccessible] protected[package lang] def finalize(): Unit
@@ -19,10 +19,8 @@ def hashCode(): Int
1919
def poke(): Unit
2020
def →[B](y: B): (Pong, B)
2121
final def !=(x$1: Any): Boolean
22-
final def !=(x$1: AnyRef): Boolean
2322
final def ##(): Int
2423
final def ==(x$1: Any): Boolean
25-
final def ==(x$1: AnyRef): Boolean
2624
final def asInstanceOf[T0]: T0
2725
final def eq(x$1: AnyRef): Boolean
2826
final def isInstanceOf[T0]: Boolean
@@ -40,7 +38,7 @@ private[this] val name: String
4038
askTypeCompletion at PingPong.scala(19,20)
4139
================================================================================
4240
[response] askTypeCompletion at (19,20)
43-
retrieved 35 members
41+
retrieved 33 members
4442
[inaccessible] protected[package lang] def clone(): Object
4543
[inaccessible] protected[package lang] def finalize(): Unit
4644
def +(other: String): String
@@ -57,10 +55,8 @@ def name: String
5755
def poke: Unit
5856
def →[B](y: B): (Ping, B)
5957
final def !=(x$1: Any): Boolean
60-
final def !=(x$1: AnyRef): Boolean
6158
final def ##(): Int
6259
final def ==(x$1: Any): Boolean
63-
final def ==(x$1: AnyRef): Boolean
6460
final def asInstanceOf[T0]: T0
6561
final def eq(x$1: AnyRef): Boolean
6662
final def isInstanceOf[T0]: Boolean

test/files/presentation/t5708.check

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ reload: Completions.scala
33
askTypeCompletion at Completions.scala(17,9)
44
================================================================================
55
[response] askTypeCompletion at (17,9)
6-
retrieved 39 members
6+
retrieved 37 members
77
[inaccessible] private def privateM: String
88
[inaccessible] private[this] val privateV: String
99
[inaccessible] private[this] val protectedV: String
@@ -22,10 +22,8 @@ def hashCode(): Int
2222
def toString(): String
2323
def →[B](y: B): (test.Compat.type, B)
2424
final def !=(x$1: Any): Boolean
25-
final def !=(x$1: AnyRef): Boolean
2625
final def ##(): Int
2726
final def ==(x$1: Any): Boolean
28-
final def ==(x$1: AnyRef): Boolean
2927
final def asInstanceOf[T0]: T0
3028
final def eq(x$1: AnyRef): Boolean
3129
final def isInstanceOf[T0]: Boolean

0 commit comments

Comments
 (0)