Skip to content

Commit e1f89fb

Browse files
authored
Merge pull request scala#9677 from dotty-staging/fix-enum-values
enum values array is constructed from field references
2 parents ecfdd11 + bdea97a commit e1f89fb

File tree

2 files changed

+30
-9
lines changed

2 files changed

+30
-9
lines changed

compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -104,22 +104,30 @@ object DesugarEnums {
104104

105105
/** The following lists of definitions for an enum type E and known value cases e_0, ..., e_n:
106106
*
107-
* private val $values = Array[E](e_0,...,e_n)(ClassTag[E](classOf[E]))
107+
* private val $values = Array[E](this.e_0,...,this.e_n)(ClassTag[E](classOf[E])): @unchecked
108108
* def values = $values.clone
109109
* def valueOf($name: String) = $name match {
110-
* case "e_0" => e_0
110+
* case "e_0" => this.e_0
111111
* ...
112-
* case "e_n" => e_n
112+
* case "e_n" => this.e_n
113113
* case _ => throw new IllegalArgumentException("case not found: " + $name)
114114
* }
115115
*/
116116
private def enumScaffolding(enumValues: List[RefTree])(using Context): List[Tree] = {
117117
val rawEnumClassRef = rawRef(enumClass.typeRef)
118118
extension (tpe: NamedType) def ofRawEnum = AppliedTypeTree(ref(tpe), rawEnumClassRef)
119119

120-
val lazyFlagOpt = if enumCompanion.owner.isStatic then EmptyFlags else Lazy
121-
val privateValuesDef = ValDef(nme.DOLLAR_VALUES, TypeTree(), ArrayLiteral(enumValues, rawEnumClassRef))
122-
.withFlags(Private | Synthetic | lazyFlagOpt)
120+
val privateValuesDef =
121+
val uncheckedValues =
122+
// Here we use an unchecked annotation to silence warnings from the init checker. Without it, we get a warning
123+
// that simple enum cases are promoting this from warm to initialised. This is because we are populating the
124+
// array by selecting enum values from `this`, a value under construction.
125+
// Singleton enum values always construct a new anonymous class, which will not be checked by the init-checker,
126+
// so this warning will always persist even if the implementation of the anonymous class is safe.
127+
// TODO: remove @unchecked after https://github.com/lampepfl/dotty-feature-requests/issues/135 is resolved.
128+
Annotated(ArrayLiteral(enumValues, rawEnumClassRef), New(ref(defn.UncheckedAnnot.typeRef)))
129+
ValDef(nme.DOLLAR_VALUES, TypeTree(), uncheckedValues)
130+
.withFlags(Private | Synthetic)
123131

124132
val valuesDef =
125133
DefDef(nme.values, Nil, Nil, defn.ArrayType.ofRawEnum, valuesDot(nme.clone_))
@@ -170,7 +178,6 @@ object DesugarEnums {
170178
* def ordinal = _$ordinal // if `E` does not derive from `java.lang.Enum`
171179
* def enumLabel = $name // if `E` does not derive from `java.lang.Enum`
172180
* def enumLabel = this.name // if `E` derives from `java.lang.Enum`
173-
* $values.register(this)
174181
* }
175182
*/
176183
private def enumValueCreator(using Context) = {
@@ -307,8 +314,8 @@ object DesugarEnums {
307314
case name: TermName => (ordinal, name) :: seenCases
308315
case _ => seenCases
309316
if definesLookups then
310-
val companionRef = ref(enumCompanion.termRef)
311-
val cachedValues = cases.reverse.map((i, name) => (i, Select(companionRef, name)))
317+
val thisRef = This(EmptyTypeIdent)
318+
val cachedValues = cases.reverse.map((i, name) => (i, Select(thisRef, name)))
312319
(ordinal, enumLookupMethods(EnumConstraints(minKind, maxKind, cachedValues)))
313320
else
314321
ctx.tree.pushAttachment(EnumCaseCount, (ordinal + 1, minKind, maxKind, cases))

tests/run/enums-thunk.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,22 @@ object Outer2 {
2020
}
2121
}
2222

23+
object Outer3 {
24+
def thunk() = {
25+
enum E { case C1 }
26+
E.C1
27+
}
28+
def thunk2() = {
29+
enum E { case C2 }
30+
E.values
31+
}
32+
}
33+
34+
2335
@main def Test =
2436
assert(Outer().thunk().toString == "A1")
2537
assert(Outer().thunk2()(0).toString == "A2")
2638
assert(Outer2.thunk().toString == "B1")
2739
assert(Outer2.thunk2()(0).toString == "B2")
40+
assert(Outer3.thunk().toString == "C1")
41+
assert(Outer3.thunk2()(0).toString == "C2")

0 commit comments

Comments
 (0)