@@ -74,57 +74,72 @@ object DesugarEnums {
7474 else if (isEnumCase(cdef)) cdef.withMods(cdef.mods.withFlags(cdef.mods.flags | Final ))
7575 else cdef
7676
77- private def valuesDot (name : String )(implicit src : SourceFile ) =
77+ private def valuesDot (name : PreName )(implicit src : SourceFile ) =
7878 Select (Ident (nme.DOLLAR_VALUES ), name.toTermName)
79+
7980 private def registerCall (implicit ctx : Context ): List [Tree ] =
8081 if (enumClass.typeParams.nonEmpty) Nil
8182 else Apply (valuesDot(" register" ), This (EmptyTypeIdent ) :: Nil ) :: Nil
8283
8384 /** The following lists of definitions for an enum type E:
8485 *
8586 * 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
8994 */
9095 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 ))
9398 val privateValuesDef =
9499 ValDef (nme.DOLLAR_VALUES , TypeTree (),
95100 New (TypeTree (defn.EnumValuesType .appliedTo(enumClass.typeRef :: Nil )), ListOfNil ))
96101 .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
101121 }
102122
103123 /** A creation method for a value of enum type `E`, which is defined as follows:
104124 *
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
108128 * $values.register(this)
109129 * }
110130 */
111131 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))
119134 val creator = New (Template (
120135 constr = emptyConstructor,
121136 parents = enumClassRef :: Nil ,
122137 derived = Nil ,
123138 self = EmptyValDef ,
124- body = List (enumTagDef , toStringDef) ++ registerCall
139+ body = List (ordinalDef , toStringDef) ++ registerCall
125140 ).withAttachment(ExtendsSingletonMirror , ()))
126141 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 ))),
128143 TypeTree (), creator).withFlags(Private | Synthetic )
129144 }
130145
@@ -232,7 +247,7 @@ object DesugarEnums {
232247 * - scaffolding containing the necessary definitions for singleton enum cases
233248 * unless that scaffolding was already generated by a previous call to `nextEnumKind`.
234249 */
235- def nextEnumTag (kind : CaseKind .Value )(implicit ctx : Context ): (Int , List [Tree ]) = {
250+ def nextOrdinal (kind : CaseKind .Value )(implicit ctx : Context ): (Int , List [Tree ]) = {
236251 val (count, seenKind) = ctx.tree.removeAttachment(EnumCaseCount ).getOrElse((0 , CaseKind .Class ))
237252 val minKind = if (kind < seenKind) kind else seenKind
238253 ctx.tree.pushAttachment(EnumCaseCount , (count + 1 , minKind))
@@ -244,14 +259,20 @@ object DesugarEnums {
244259 (count, scaffolding)
245260 }
246261
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)))
255276
256277 /** Expand a module definition representing a parameterless enum case */
257278 def expandEnumModule (name : TermName , impl : Template , mods : Modifiers , span : Span )(implicit ctx : Context ): Tree = {
@@ -260,11 +281,10 @@ object DesugarEnums {
260281 else if (impl.parents.isEmpty)
261282 expandSimpleEnumCase(name, mods, span)
262283 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)
268288 .withAttachment(ExtendsSingletonMirror , ())
269289 val vdef = ValDef (name, TypeTree (), New (impl1)).withMods(mods | Final )
270290 flatTree(scaffolding ::: vdef :: Nil ).withSpan(span)
@@ -280,7 +300,7 @@ object DesugarEnums {
280300 expandEnumModule(name, impl, mods, span)
281301 }
282302 else {
283- val (tag, scaffolding) = nextEnumTag (CaseKind .Simple )
303+ val (tag, scaffolding) = nextOrdinal (CaseKind .Simple )
284304 val creator = Apply (Ident (nme.DOLLAR_NEW ), List (Literal (Constant (tag)), Literal (Constant (name.toString))))
285305 val vdef = ValDef (name, enumClassRef, creator).withMods(mods | Final )
286306 flatTree(scaffolding ::: vdef :: Nil ).withSpan(span)
0 commit comments