Skip to content

Commit

Permalink
Compare productPrefix in synthetic case class canEqual
Browse files Browse the repository at this point in the history
Since 2.13, case class `hashCode` mixes in the hash code of the
`productPrefix` string. The synthetic `equals` method has fallen
out of sync in that regard, so two instances can be equal but have
different hash codes.

This commit changes the synthetic `canEqual` method to also compare
the `productPrefix` of the two instances.
  • Loading branch information
lrytz committed Sep 18, 2024
1 parent 6e852d2 commit 1ca4139
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,13 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
*
* `@unchecked` is needed for parametric case classes.
*/
def canEqualBody(that: Tree, span: Span): Tree = that.isInstance(AnnotatedType(clazzType, Annotation(defn.UncheckedAnnot, span)))
def canEqualBody(that: Tree, span: Span): Tree = {
val clazzTypeU = AnnotatedType(clazzType, Annotation(defn.UncheckedAnnot, span))
that.isInstance(clazzTypeU).and(
This(clazz).select(defn.Product_productPrefix)
.select(defn.Any_==)
.appliedTo(that.cast(clazzTypeU).select(defn.Product_productPrefix)))
}

symbolsToSynthesize.flatMap(syntheticDefIfMissing)
}
Expand Down
24 changes: 24 additions & 0 deletions tests/run/t13033.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
case class C(x: Int)
class D extends C(1) { override def productPrefix = "D" }

abstract case class C1(a: Int)
class C2(a: Int) extends C1(a) { override def productPrefix = "C2" }
class C3(a: Int) extends C1(a) { override def productPrefix = "C3" }

case class VCC(x: Int) extends AnyVal

object Test extends App {
val c = C(1)
assert(c != new D)
assert(c == C(1))
assert(!c.canEqual(new D))

val c2 = new C2(1)
val c3 = new C3(1)
assert(c2 != c3)
assert(c2.hashCode != c3.hashCode)
assert(!c2.canEqual(c3))

assert(VCC(1).canEqual(VCC(1)))
assert(!VCC(1).canEqual(1))
}

0 comments on commit 1ca4139

Please sign in to comment.