@@ -119,7 +119,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
119119
120120 def syntheticRHS (vrefss : List [List [Tree ]])(implicit ctx : Context ): Tree = synthetic.name match {
121121 case nme.hashCode_ if isDerivedValueClass(clazz) => valueHashCodeBody
122- case nme.hashCode_ => caseHashCodeBody
122+ case nme.hashCode_ => chooseHashcode
123123 case nme.toString_ => if (clazz.is(ModuleClass )) ownName else forwardToRuntime(vrefss.head)
124124 case nme.equals_ => equalsBody(vrefss.head.head)
125125 case nme.canEqual_ => canEqualBody(vrefss.head.head)
@@ -232,35 +232,65 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
232232 /** The class
233233 *
234234 * ```
235- * package p
236- * case class C(x: T, y: T)
235+ * case object C
236+ * ```
237+ *
238+ * gets the `hashCode` method:
239+ *
240+ * ```
241+ * "C".hashCode // constant folded
242+ * ```
243+ *
244+ * The class
245+ *
246+ * ```
247+ * case class C(x: T, y: U)
248+ * ```
249+ *
250+ * if non of `T` or `U` are primitive types, gets the `hashCode` method:
251+ *
252+ * ```
253+ * def hashCode: Int = ScalaRunTime._hashCode(this)
254+ * ```
255+ *
256+ * else if either `T` or `U` are primitive, gets the `hashCode` method implemented by [[caseHashCodeBody ]]
257+ */
258+ def chooseHashcode (implicit ctx : Context ) = {
259+ if clazz.is(ModuleClass ) then
260+ Literal (Constant (clazz.name.stripModuleClassSuffix.toString.hashCode))
261+ else if accessors `exists` (_.info.finalResultType.classSymbol.isPrimitiveValueClass) then
262+ caseHashCodeBody
263+ else
264+ ref(defn.ScalaRuntimeModule ).select(" _hashCode" .toTermName).appliedTo(This (clazz))
265+ }
266+
267+ /** The class
268+ *
269+ * ```
270+ * case class C(x: Int, y: T)
237271 * ```
238272 *
239273 * gets the `hashCode` method:
240274 *
241275 * ```
242276 * def hashCode: Int = {
243- * <synthetic> var acc: Int = "p.C".hashCode // constant folded
277+ * <synthetic> var acc: Int = 0xcafebabe
278+ * acc = Statics.mix(acc, this.productPrefix.hashCode);
244279 * acc = Statics.mix(acc, x);
245280 * acc = Statics.mix(acc, Statics.this.anyHash(y));
246281 * Statics.finalizeHash(acc, 2)
247282 * }
248283 * ```
249284 */
250285 def caseHashCodeBody (implicit ctx : Context ): Tree = {
251- val seed = clazz.fullName.toString.hashCode
252- if (accessors.nonEmpty) {
253- val acc = ctx.newSymbol(ctx.owner, " acc" .toTermName, Mutable | Synthetic , defn.IntType , coord = ctx.owner.span)
254- val accDef = ValDef (acc, Literal (Constant (seed)))
255- val mixes = for (accessor <- accessors) yield
256- Assign (ref(acc), ref(defn.staticsMethod(" mix" )).appliedTo(ref(acc), hashImpl(accessor)))
257- val finish = ref(defn.staticsMethod(" finalizeHash" )).appliedTo(ref(acc), Literal (Constant (accessors.size)))
258- Block (accDef :: mixes, finish)
259- } else {
260- // Pre-compute the hash code
261- val hash = scala.runtime.Statics .finalizeHash(seed, 0 )
262- Literal (Constant (hash))
263- }
286+ val acc = ctx.newSymbol(ctx.owner, " acc" .toTermName, Mutable | Synthetic , defn.IntType , coord = ctx.owner.span)
287+ val accDef = ValDef (acc, Literal (Constant (0xcafebabe )))
288+ val mixPrefix = Assign (ref(acc),
289+ ref(defn.staticsMethod(" mix" )).appliedTo(ref(acc), This (clazz).select(defn.Product_productPrefix ).select(defn.Any_hashCode )))
290+ val mixes = for accessor <- accessors yield
291+ Assign (ref(acc), ref(defn.staticsMethod(" mix" )).appliedTo(ref(acc), hashImpl(accessor)))
292+ val finish = ref(defn.staticsMethod(" finalizeHash" )).appliedTo(ref(acc), Literal (Constant (accessors.size)))
293+ Block (accDef :: mixPrefix :: mixes, finish)
264294 }
265295
266296 /** The `hashCode` implementation for given symbol `sym`. */
0 commit comments