@@ -15,6 +15,9 @@ import DenotTransformers._
15
15
import dotty .tools .dotc .ast .Trees ._
16
16
import SymUtils ._
17
17
18
+ import annotation .threadUnsafe
19
+ import collection .mutable
20
+
18
21
object CompleteJavaEnums {
19
22
val name : String = " completeJavaEnums"
20
23
@@ -40,10 +43,6 @@ class CompleteJavaEnums extends MiniPhase with InfoTransformer { thisPhase =>
40
43
sym == defn.JavaEnumClass .primaryConstructor ||
41
44
sym.owner.derivesFromJavaEnum))
42
45
addConstrParams(sym.info)
43
- else if isJavaEnumValueImpl(sym) then
44
- sym.asClass.delete(tp.decl(nme.toString_).symbol)
45
- sym.asClass.delete(tp.decl(nme.ordinalDollar).symbol)
46
- tp
47
46
else tp
48
47
49
48
/** Add constructor parameters `$name: String` and `$ordinal: Int` to the end of
@@ -114,37 +113,42 @@ class CompleteJavaEnums extends MiniPhase with InfoTransformer { thisPhase =>
114
113
115
114
private def isJavaEnumValueImpl (cls : Symbol )(using Context ): Boolean =
116
115
cls.isAnonymousClass
117
- && ((cls.owner.name eq nme.DOLLAR_NEW ) || cls.owner.isAllOf(EnumCase ))
118
- && {
119
- val enumCls = cls.owner.owner.linkedClass
120
- enumCls.derivesFromJavaEnum && enumCls.is(Enum )
121
- }
116
+ && (((cls.owner.name eq nme.DOLLAR_NEW ) && cls.owner.isAllOf(Private | Synthetic )) || cls.owner.isAllOf(EnumCase ))
117
+ && cls.owner.owner.linkedClass.derivesFromJavaEnum
118
+
119
+ @ threadUnsafe
120
+ private lazy val enumCaseOrdinals : mutable.Map [Symbol , Int ] = mutable.AnyRefMap .empty
121
+
122
+ private def registerEnumClass (cls : Symbol )(using Context ): Unit =
123
+ cls.children.zipWithIndex.foreach(enumCaseOrdinals.put)
124
+
125
+ private def ordinalFor (enumCase : Symbol ): Int = enumCaseOrdinals.remove(enumCase).get
122
126
123
127
/** 1. If this is an enum class, add $name and $ordinal parameters to its
124
128
* parameter accessors and pass them on to the java.lang.Enum constructor.
125
129
*
126
- * 2. If this is an anonymous class that implement a value enum case,
130
+ * 2. If this is an anonymous class that implement a singleton enum case,
127
131
* pass $name and $ordinal parameters to the enum superclass. The class
128
132
* looks like this:
129
133
*
130
134
* class $anon extends E(...) {
131
135
* ...
132
- * private def $ordinal = N
133
- * override def toString = S
134
- * ...
135
136
* }
136
137
*
137
138
* After the transform it is expanded to
138
139
*
139
- * class $anon extends E(..., N, S) {
140
- * ...
141
- * "removed $ordinal and toString"
142
- * ...
140
+ * class $anon extends E(..., $name, _$ordinal) { // if class implements a simple enum case
141
+ * "same as before"
142
+ * }
143
+ *
144
+ * class $anon extends E(..., "A", 0) { // if class implements a value enum case `A` with ordinal 0
145
+ * "same as before"
143
146
* }
144
147
*/
145
148
override def transformTemplate (templ : Template )(using Context ): Template = {
146
149
val cls = templ.symbol.owner
147
150
if cls.derivesFromJavaEnum then
151
+ registerEnumClass(cls)
148
152
val (params, rest) = decomposeTemplateBody(templ.body)
149
153
val addedDefs = addedParams(cls, isLocal= true , ParamAccessor )
150
154
val addedSyms = addedDefs.map(_.symbol.entered)
@@ -153,14 +157,15 @@ class CompleteJavaEnums extends MiniPhase with InfoTransformer { thisPhase =>
153
157
parents = addEnumConstrArgs(defn.JavaEnumClass , templ.parents, addedSyms.map(ref)),
154
158
body = params ++ addedDefs ++ addedForwarders ++ rest)
155
159
else if isJavaEnumValueImpl(cls) then
156
- def rhsOf (name : TermName ) =
157
- templ.body.collect({ case mdef : DefDef if mdef.name == name => mdef.rhs }).head
158
- def removeDefs (body : List [Tree ], names : TermName * ) =
159
- body.filterNot { case ndef : DefDef => names.contains(ndef.name); case _ => false }
160
- val args = List (rhsOf(nme.toString_), rhsOf(nme.ordinalDollar))
160
+ def creatorParamRef (name : TermName ) =
161
+ ref(cls.owner.paramSymss.head.find(_.name == name).get)
162
+ val args =
163
+ if cls.owner.isAllOf(EnumCase ) then
164
+ List (Literal (Constant (cls.owner.name.toString)), Literal (Constant (ordinalFor(cls.owner))))
165
+ else
166
+ List (creatorParamRef(nme.nameDollar), creatorParamRef(nme.ordinalDollar_))
161
167
cpy.Template (templ)(
162
168
parents = addEnumConstrArgs(cls.owner.owner.linkedClass, templ.parents, args),
163
- body = removeDefs(templ.body, nme.toString_, nme.ordinalDollar)
164
169
)
165
170
else templ
166
171
}
0 commit comments