@@ -119,7 +119,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
119
119
120
120
def syntheticRHS (vrefss : List [List [Tree ]])(implicit ctx : Context ): Tree = synthetic.name match {
121
121
case nme.hashCode_ if isDerivedValueClass(clazz) => valueHashCodeBody
122
- case nme.hashCode_ => caseHashCodeBody
122
+ case nme.hashCode_ => chooseHashcode
123
123
case nme.toString_ => if (clazz.is(ModuleClass )) ownName else forwardToRuntime(vrefss.head)
124
124
case nme.equals_ => equalsBody(vrefss.head.head)
125
125
case nme.canEqual_ => canEqualBody(vrefss.head.head)
@@ -232,35 +232,65 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
232
232
/** The class
233
233
*
234
234
* ```
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)
237
271
* ```
238
272
*
239
273
* gets the `hashCode` method:
240
274
*
241
275
* ```
242
276
* 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);
244
279
* acc = Statics.mix(acc, x);
245
280
* acc = Statics.mix(acc, Statics.this.anyHash(y));
246
281
* Statics.finalizeHash(acc, 2)
247
282
* }
248
283
* ```
249
284
*/
250
285
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)
264
294
}
265
295
266
296
/** The `hashCode` implementation for given symbol `sym`. */
0 commit comments