Skip to content

Commit 5f40270

Browse files
committed
enum values array is constructed from field references
This patches a regression introduced in #9628 where defining an enum local to a method can cause an infinite loop at initialisation of its companion. Instead, we select enum values from "this" and not the companion, which avoids forcing initialisation of the companion. We then ascribe the values array with unchecked annotation to avoid complaints from the init checker.
1 parent 4c99388 commit 5f40270

File tree

2 files changed

+22
-7
lines changed

2 files changed

+22
-7
lines changed

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ 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](e_0,...,e_n)(ClassTag[E](classOf[E])): @unchecked
108108
* def values = $values.clone
109109
* def valueOf($name: String) = $name match {
110110
* case "e_0" => e_0
@@ -117,9 +117,11 @@ object DesugarEnums {
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+
Annotated(ArrayLiteral(enumValues, rawEnumClassRef), New(ref(defn.UncheckedAnnot.typeRef)))
123+
ValDef(nme.DOLLAR_VALUES, TypeTree(), uncheckedValues)
124+
.withFlags(Private | Synthetic)
123125

124126
val valuesDef =
125127
DefDef(nme.values, Nil, Nil, defn.ArrayType.ofRawEnum, valuesDot(nme.clone_))
@@ -170,7 +172,6 @@ object DesugarEnums {
170172
* def ordinal = _$ordinal // if `E` does not derive from `java.lang.Enum`
171173
* def enumLabel = $name // if `E` does not derive from `java.lang.Enum`
172174
* def enumLabel = this.name // if `E` derives from `java.lang.Enum`
173-
* $values.register(this)
174175
* }
175176
*/
176177
private def enumValueCreator(using Context) = {
@@ -307,8 +308,8 @@ object DesugarEnums {
307308
case name: TermName => (ordinal, name) :: seenCases
308309
case _ => seenCases
309310
if definesLookups then
310-
val companionRef = ref(enumCompanion.termRef)
311-
val cachedValues = cases.reverse.map((i, name) => (i, Select(companionRef, name)))
311+
val thisRef = This(EmptyTypeIdent)
312+
val cachedValues = cases.reverse.map((i, name) => (i, Select(thisRef, name)))
312313
(ordinal, enumLookupMethods(EnumConstraints(minKind, maxKind, cachedValues)))
313314
else
314315
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)