diff --git a/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala b/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala index 4bc9575996d1..4fd33f7e7155 100644 --- a/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala +++ b/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala @@ -68,7 +68,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) { myCaseSymbols = defn.caseClassSynthesized myCaseModuleSymbols = myCaseSymbols.filter(_ ne defn.Any_equals) myEnumValueSymbols = List(defn.Product_productPrefix) - myNonJavaEnumValueSymbols = myEnumValueSymbols :+ defn.Any_toString :+ defn.Enum_ordinal + myNonJavaEnumValueSymbols = myEnumValueSymbols :+ defn.Any_toString :+ defn.Enum_ordinal :+ defn.Any_hashCode } def valueSymbols(using Context): List[Symbol] = { initSymbols; myValueSymbols } @@ -116,6 +116,12 @@ class SyntheticMembers(thisPhase: DenotTransformer) { def syntheticDefIfMissing(sym: Symbol): List[Tree] = if (existingDef(sym, clazz).exists) Nil else syntheticDef(sym) :: Nil + def identifierRef: Tree = + if isSimpleEnumValue then // owner is `def $new(_$ordinal: Int, $name: String) = new MyEnum { ... }` + ref(clazz.owner.paramSymss.head.find(_.name == nme.nameDollar).get) + else // assume owner is `val Foo = new MyEnum { def ordinal = 0 }` + Literal(Constant(clazz.owner.name.toString)) + def syntheticDef(sym: Symbol): Tree = { val synthetic = sym.copy( owner = clazz, @@ -135,12 +141,6 @@ class SyntheticMembers(thisPhase: DenotTransformer) { else identifierRef - def identifierRef: Tree = - if isSimpleEnumValue then // owner is `def $new(_$ordinal: Int, $name: String) = new MyEnum { ... }` - ref(clazz.owner.paramSymss.head.find(_.name == nme.nameDollar).get) - else // assume owner is `val Foo = new MyEnum { def ordinal = 0 }` - Literal(Constant(clazz.owner.name.toString)) - def ordinalRef: Tree = if isSimpleEnumValue then // owner is `def $new(_$ordinal: Int, $name: String) = new MyEnum { ... }` ref(clazz.owner.paramSymss.head.find(_.name == nme.ordinalDollar_).get) @@ -357,7 +357,8 @@ class SyntheticMembers(thisPhase: DenotTransformer) { * For case classes with primitive paramters, see [[caseHashCodeBody]]. */ def chooseHashcode(using Context) = - if (accessors.isEmpty) Literal(Constant(ownName.hashCode)) + if (isNonJavaEnumValue) identifierRef.select(nme.hashCode_).appliedToTermArgs(Nil) + else if (accessors.isEmpty) Literal(Constant(ownName.hashCode)) else if (accessors.exists(_.info.finalResultType.classSymbol.isPrimitiveValueClass)) caseHashCodeBody else diff --git a/tests/run/stable-enum-hashcodes.check b/tests/run/stable-enum-hashcodes.check new file mode 100644 index 000000000000..2a3cb493c4c9 --- /dev/null +++ b/tests/run/stable-enum-hashcodes.check @@ -0,0 +1,12 @@ +65 +65 +66 +66 +67 +67 +68 +68 +-1449359058 +-1449359058 +194551161 +194551161 diff --git a/tests/run/stable-enum-hashcodes.scala b/tests/run/stable-enum-hashcodes.scala new file mode 100644 index 000000000000..60b5af11e437 --- /dev/null +++ b/tests/run/stable-enum-hashcodes.scala @@ -0,0 +1,23 @@ +enum Enum: + case A + case B + case C() + case D() + case E(x: Int) + +@main def Test = + // Enum values (were not stable from run to run before #23218) + println(Enum.A.hashCode) + println(Enum.A.hashCode) + println(Enum.B.hashCode) + println(Enum.B.hashCode) + + // Other enum cases (were already stable from run to run) + println(Enum.C().hashCode) + println(Enum.C().hashCode) + println(Enum.D().hashCode) + println(Enum.D().hashCode) + println(Enum.E(1).hashCode) + println(Enum.E(1).hashCode) + println(Enum.E(2).hashCode) + println(Enum.E(2).hashCode)