From e2ec1bf182c98272ea7f88dca1900f0ba633222b Mon Sep 17 00:00:00 2001 From: tim-zh Date: Thu, 6 Dec 2018 18:05:47 +0300 Subject: [PATCH] Add fields sorting (primitives first) in case class equals --- .../dotty/tools/dotc/transform/SyntheticMethods.scala | 4 +++- tests/run/case_class_equals_fields_sort.scala | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 tests/run/case_class_equals_fields_sort.scala diff --git a/compiler/src/dotty/tools/dotc/transform/SyntheticMethods.scala b/compiler/src/dotty/tools/dotc/transform/SyntheticMethods.scala index 0b9dde117732..bb2f6c9f6dc4 100644 --- a/compiler/src/dotty/tools/dotc/transform/SyntheticMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/SyntheticMethods.scala @@ -161,7 +161,9 @@ class SyntheticMethods(thisPhase: DenotTransformer) { val thatAsClazz = ctx.newSymbol(ctx.owner, nme.x_0, Synthetic, clazzType, coord = ctx.owner.pos) // x$0 def wildcardAscription(tp: Type) = Typed(Underscore(tp), TypeTree(tp)) val pattern = Bind(thatAsClazz, wildcardAscription(AnnotatedType(clazzType, Annotation(defn.UncheckedAnnot)))) // x$0 @ (_: C @unchecked) - val comparisons = accessors map { accessor => + // compare primitive fields first, slow equality checks of non-primitive fields can be skipped when primitives differ + val sortedAccessors = accessors.sortBy(accessor => if (accessor.info.typeSymbol.isPrimitiveValueClass) 0 else 1) + val comparisons = sortedAccessors.map { accessor => This(clazz).select(accessor).equal(ref(thatAsClazz).select(accessor)) } val rhs = // this.x == this$0.x && this.y == x$0.y if (comparisons.isEmpty) Literal(Constant(true)) else comparisons.reduceLeft(_ and _) diff --git a/tests/run/case_class_equals_fields_sort.scala b/tests/run/case_class_equals_fields_sort.scala new file mode 100644 index 000000000000..01c6a2207a15 --- /dev/null +++ b/tests/run/case_class_equals_fields_sort.scala @@ -0,0 +1,9 @@ +object Test { + def main(args: Array[String]): Unit = { + class X { override def equals(x: Any) = throw new Exception("shouldn't be called") } + case class C(x: X, i: Int) + val x = new X + + C(x, 1) == C(x, 2) + } +}