@@ -74,57 +74,72 @@ object DesugarEnums {
74
74
else if (isEnumCase(cdef)) cdef.withMods(cdef.mods.withFlags(cdef.mods.flags | Final ))
75
75
else cdef
76
76
77
- private def valuesDot (name : String )(implicit src : SourceFile ) =
77
+ private def valuesDot (name : PreName )(implicit src : SourceFile ) =
78
78
Select (Ident (nme.DOLLAR_VALUES ), name.toTermName)
79
+
79
80
private def registerCall (implicit ctx : Context ): List [Tree ] =
80
81
if (enumClass.typeParams.nonEmpty) Nil
81
82
else Apply (valuesDot(" register" ), This (EmptyTypeIdent ) :: Nil ) :: Nil
82
83
83
84
/** The following lists of definitions for an enum type E:
84
85
*
85
86
* private val $values = new EnumValues[E]
86
- * def enumValue = $values.fromInt
87
- * def enumValueNamed = $values.fromName
88
- * def enumValues = $values.values
87
+ * def valueOf($name: String) =
88
+ * try $values.fromName($name) catch
89
+ * {
90
+ * case ex$:NoSuchElementException =>
91
+ * throw new IllegalArgumentException("key not found: ".concat(name))
92
+ * }
93
+ * def values = $values.values.toArray
89
94
*/
90
95
private def enumScaffolding (implicit ctx : Context ): List [Tree ] = {
91
- def enumDefDef ( name : String , select : String ) =
92
- DefDef (name.toTermName , Nil , Nil , TypeTree (), valuesDot(select ))
96
+ val valuesDef =
97
+ DefDef (nme.values , Nil , Nil , TypeTree (), Select ( valuesDot(nme.values), nme.toArray ))
93
98
val privateValuesDef =
94
99
ValDef (nme.DOLLAR_VALUES , TypeTree (),
95
100
New (TypeTree (defn.EnumValuesType .appliedTo(enumClass.typeRef :: Nil )), ListOfNil ))
96
101
.withFlags(Private )
97
- val valueOfDef = enumDefDef(" enumValue" , " fromInt" )
98
- val withNameDef = enumDefDef(" enumValueNamed" , " fromName" )
99
- val valuesDef = enumDefDef(" enumValues" , " values" )
100
- List (privateValuesDef, valueOfDef, withNameDef, valuesDef)
102
+
103
+ val valuesOfExnMessage = Apply (
104
+ Select (Literal (Constant (" key not found: " )), " concat" .toTermName),
105
+ Ident (nme.nameDollar) :: Nil )
106
+ val valuesOfBody = Try (
107
+ expr = Apply (valuesDot(" fromName" ), Ident (nme.nameDollar) :: Nil ),
108
+ cases = CaseDef (
109
+ pat = Typed (Ident (nme.DEFAULT_EXCEPTION_NAME ), TypeTree (defn.NoSuchElementExceptionType )),
110
+ guard = EmptyTree ,
111
+ body = Throw (New (TypeTree (defn.IllegalArgumentExceptionType ), List (valuesOfExnMessage :: Nil )))
112
+ ) :: Nil ,
113
+ finalizer = EmptyTree
114
+ )
115
+ val valueOfDef = DefDef (nme.valueOf, Nil , List (param(nme.nameDollar, defn.StringType ) :: Nil ),
116
+ TypeTree (), valuesOfBody)
117
+
118
+ valuesDef ::
119
+ privateValuesDef ::
120
+ valueOfDef :: Nil
101
121
}
102
122
103
123
/** A creation method for a value of enum type `E`, which is defined as follows:
104
124
*
105
- * private def $new(tag : Int, name: String) = new E {
106
- * def enumTag = tag
107
- * override def toString = name
125
+ * private def $new(_$ordinal : Int, $ name: String) = new E {
126
+ * def $ordinal = $ tag
127
+ * override def toString = $ name
108
128
* $values.register(this)
109
129
* }
110
130
*/
111
131
private def enumValueCreator (implicit ctx : Context ) = {
112
- def param (name : TermName , typ : Type ) =
113
- ValDef (name, TypeTree (typ), EmptyTree ).withFlags(Param )
114
- val enumTagDef =
115
- DefDef (nme.enumTag, Nil , Nil , TypeTree (), Ident (nme.tag))
116
- val toStringDef =
117
- DefDef (nme.toString_, Nil , Nil , TypeTree (), Ident (nme.name))
118
- .withFlags(Override )
132
+ val ordinalDef = ordinalMeth(Ident (nme.ordinalDollar_))
133
+ val toStringDef = toStringMeth(Ident (nme.nameDollar))
119
134
val creator = New (Template (
120
135
constr = emptyConstructor,
121
136
parents = enumClassRef :: Nil ,
122
137
derived = Nil ,
123
138
self = EmptyValDef ,
124
- body = List (enumTagDef , toStringDef) ++ registerCall
139
+ body = List (ordinalDef , toStringDef) ++ registerCall
125
140
).withAttachment(ExtendsSingletonMirror , ()))
126
141
DefDef (nme.DOLLAR_NEW , Nil ,
127
- List (List (param(nme.tag , defn.IntType ), param(nme.name , defn.StringType ))),
142
+ List (List (param(nme.ordinalDollar_ , defn.IntType ), param(nme.nameDollar , defn.StringType ))),
128
143
TypeTree (), creator).withFlags(Private | Synthetic )
129
144
}
130
145
@@ -232,7 +247,7 @@ object DesugarEnums {
232
247
* - scaffolding containing the necessary definitions for singleton enum cases
233
248
* unless that scaffolding was already generated by a previous call to `nextEnumKind`.
234
249
*/
235
- def nextEnumTag (kind : CaseKind .Value )(implicit ctx : Context ): (Int , List [Tree ]) = {
250
+ def nextOrdinal (kind : CaseKind .Value )(implicit ctx : Context ): (Int , List [Tree ]) = {
236
251
val (count, seenKind) = ctx.tree.removeAttachment(EnumCaseCount ).getOrElse((0 , CaseKind .Class ))
237
252
val minKind = if (kind < seenKind) kind else seenKind
238
253
ctx.tree.pushAttachment(EnumCaseCount , (count + 1 , minKind))
@@ -244,14 +259,20 @@ object DesugarEnums {
244
259
(count, scaffolding)
245
260
}
246
261
247
- /** A pair consisting of
248
- * - a method returning the next enum tag
249
- * - scaffolding as defined in `nextEnumTag`
250
- */
251
- def enumTagMeth (kind : CaseKind .Value )(implicit ctx : Context ): (DefDef , List [Tree ]) = {
252
- val (tag, scaffolding) = nextEnumTag(kind)
253
- (DefDef (nme.enumTag, Nil , Nil , TypeTree (), Literal (Constant (tag))), scaffolding)
254
- }
262
+ def param (name : TermName , typ : Type )(implicit ctx : Context ) =
263
+ ValDef (name, TypeTree (typ), EmptyTree ).withFlags(Param )
264
+
265
+ def ordinalMeth (body : Tree )(implicit ctx : Context ): DefDef =
266
+ DefDef (nme.ordinalDollar, Nil , Nil , TypeTree (defn.IntType ), body)
267
+
268
+ def toStringMeth (body : Tree )(implicit ctx : Context ): DefDef =
269
+ DefDef (nme.toString_, Nil , Nil , TypeTree (defn.StringType ), body).withFlags(Override )
270
+
271
+ def ordinalMethLit (ord : Int )(implicit ctx : Context ): DefDef =
272
+ ordinalMeth(Literal (Constant (ord)))
273
+
274
+ def toStringMethLit (name : String )(implicit ctx : Context ): DefDef =
275
+ toStringMeth(Literal (Constant (name)))
255
276
256
277
/** Expand a module definition representing a parameterless enum case */
257
278
def expandEnumModule (name : TermName , impl : Template , mods : Modifiers , span : Span )(implicit ctx : Context ): Tree = {
@@ -260,11 +281,10 @@ object DesugarEnums {
260
281
else if (impl.parents.isEmpty)
261
282
expandSimpleEnumCase(name, mods, span)
262
283
else {
263
- def toStringMeth =
264
- DefDef (nme.toString_, Nil , Nil , TypeTree (defn.StringType ), Literal (Constant (name.toString)))
265
- .withFlags(Override )
266
- val (tagMeth, scaffolding) = enumTagMeth(CaseKind .Object )
267
- val impl1 = cpy.Template (impl)(body = List (tagMeth, toStringMeth) ++ registerCall)
284
+ val (tag, scaffolding) = nextOrdinal(CaseKind .Object )
285
+ val ordinalDef = ordinalMethLit(tag)
286
+ val toStringDef = toStringMethLit(name.toString)
287
+ val impl1 = cpy.Template (impl)(body = List (ordinalDef, toStringDef) ++ registerCall)
268
288
.withAttachment(ExtendsSingletonMirror , ())
269
289
val vdef = ValDef (name, TypeTree (), New (impl1)).withMods(mods | Final )
270
290
flatTree(scaffolding ::: vdef :: Nil ).withSpan(span)
@@ -280,7 +300,7 @@ object DesugarEnums {
280
300
expandEnumModule(name, impl, mods, span)
281
301
}
282
302
else {
283
- val (tag, scaffolding) = nextEnumTag (CaseKind .Simple )
303
+ val (tag, scaffolding) = nextOrdinal (CaseKind .Simple )
284
304
val creator = Apply (Ident (nme.DOLLAR_NEW ), List (Literal (Constant (tag)), Literal (Constant (name.toString))))
285
305
val vdef = ValDef (name, enumClassRef, creator).withMods(mods | Final )
286
306
flatTree(scaffolding ::: vdef :: Nil ).withSpan(span)
0 commit comments