Skip to content

Commit 91a26b3

Browse files
committed
Support comma-separated enum constants
1 parent cf10e28 commit 91a26b3

File tree

5 files changed

+48
-30
lines changed

5 files changed

+48
-30
lines changed

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -576,11 +576,23 @@ object desugar {
576576
/** val p1, ..., pN: T = E
577577
* ==>
578578
* makePatDef[[val p1: T1 = E]]; ...; makePatDef[[val pN: TN = E]]
579+
*
580+
* case e1, ..., eN
581+
* ==>
582+
* expandSimpleEnumCase([case e1]); ...; expandSimpleEnumCase([case eN])
579583
*/
580-
def patDef(pdef: PatDef)(implicit ctx: Context): Tree = {
584+
def patDef(pdef: PatDef)(implicit ctx: Context): Tree = flatTree {
581585
val PatDef(mods, pats, tpt, rhs) = pdef
582-
val pats1 = if (tpt.isEmpty) pats else pats map (Typed(_, tpt))
583-
flatTree(pats1 map (makePatDef(pdef, mods, _, rhs)))
586+
if (mods.hasMod[Mod.EnumCase] && enumCaseIsLegal(pdef))
587+
pats map {
588+
case id: Ident =>
589+
expandSimpleEnumCase(id.name.asTermName, mods,
590+
Position(pdef.pos.start, id.pos.end, id.pos.start))
591+
}
592+
else {
593+
val pats1 = if (tpt.isEmpty) pats else pats map (Typed(_, tpt))
594+
pats1 map (makePatDef(pdef, mods, _, rhs))
595+
}
584596
}
585597

586598
/** If `pat` is a variable pattern,

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

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,15 @@ object DesugarEnums {
2424
result
2525
}
2626

27-
def isLegalEnumCase(tree: MemberDef)(implicit ctx: Context): Boolean = {
28-
tree.mods.hasMod[Mod.EnumCase] &&
29-
( ctx.owner.is(ModuleClass) && enumClass.derivesFrom(defn.EnumClass)
27+
def isLegalEnumCase(tree: MemberDef)(implicit ctx: Context): Boolean =
28+
tree.mods.hasMod[Mod.EnumCase] && enumCaseIsLegal(tree)
29+
30+
def enumCaseIsLegal(tree: Tree)(implicit ctx: Context): Boolean = (
31+
ctx.owner.is(ModuleClass) && enumClass.derivesFrom(defn.EnumClass)
3032
|| { ctx.error(em"case not allowed here, since owner ${ctx.owner} is not an `enum' object", tree.pos)
3133
false
3234
}
3335
)
34-
}
3536

3637
/** Type parameters reconstituted from the constructor
3738
* of the `enum' class corresponding to an enum case.
@@ -104,23 +105,25 @@ object DesugarEnums {
104105
List(privateValuesDef, valueOfDef, withNameDef, valuesDef, newDef)
105106
}
106107

107-
def expandEnumModule(name: TermName, impl: Template, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree = {
108-
def nameLit = Literal(Constant(name.toString))
109-
if (impl.parents.isEmpty) {
110-
if (reconstitutedEnumTypeParams(pos).nonEmpty)
111-
ctx.error(i"illegal enum value of generic $enumClass: an explicit `extends' clause is needed", pos)
112-
val tag = nextEnumTag
113-
val prefix = if (tag == 0) enumScaffolding else Nil
114-
val creator = Apply(Ident(nme.DOLLAR_NEW), List(Literal(Constant(tag)), nameLit))
115-
val vdef = ValDef(name, enumClassRef, creator).withMods(mods | Final).withPos(pos)
116-
flatTree(prefix ::: vdef :: Nil).withPos(pos.startPos)
117-
} else {
108+
def expandEnumModule(name: TermName, impl: Template, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree =
109+
if (impl.parents.isEmpty)
110+
expandSimpleEnumCase(name, mods, pos)
111+
else {
118112
def toStringMeth =
119-
DefDef(nme.toString_, Nil, Nil, TypeTree(defn.StringType), nameLit)
113+
DefDef(nme.toString_, Nil, Nil, TypeTree(defn.StringType), Literal(Constant(name.toString)))
120114
.withFlags(Override)
121115
val impl1 = cpy.Template(impl)(body =
122116
impl.body ++ List(enumTagMeth, toStringMeth))
123117
ValDef(name, TypeTree(), New(impl1)).withMods(mods | Final).withPos(pos)
124118
}
119+
120+
def expandSimpleEnumCase(name: TermName, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree = {
121+
if (reconstitutedEnumTypeParams(pos).nonEmpty)
122+
ctx.error(i"illegal enum value of generic $enumClass: an explicit `extends' clause is needed", pos)
123+
val tag = nextEnumTag
124+
val prefix = if (tag == 0) enumScaffolding else Nil
125+
val creator = Apply(Ident(nme.DOLLAR_NEW), List(Literal(Constant(tag)), Literal(Constant(name.toString))))
126+
val vdef = ValDef(name, enumClassRef, creator).withMods(mods | Final).withPos(pos)
127+
flatTree(prefix ::: vdef :: Nil).withPos(pos.startPos)
125128
}
126129
}

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2149,8 +2149,8 @@ object Parsers {
21492149
}
21502150

21512151
/** EnumCaseStats = EnumCaseStat {semi EnumCaseStat */
2152-
def enumCaseStats(): List[MemberDef] = {
2153-
val cases = new ListBuffer[MemberDef] += enumCaseStat()
2152+
def enumCaseStats(): List[DefTree] = {
2153+
val cases = new ListBuffer[DefTree] += enumCaseStat()
21542154
while (in.token != RBRACE) {
21552155
acceptStatSep()
21562156
cases += enumCaseStat()
@@ -2159,19 +2159,24 @@ object Parsers {
21592159
}
21602160

21612161
/** EnumCaseStat = {Annotation [nl]} {Modifier} EnumCase */
2162-
def enumCaseStat(): MemberDef =
2162+
def enumCaseStat(): DefTree =
21632163
enumCase(in.offset, defAnnotsMods(modifierTokens))
21642164

21652165
/** EnumCase = `case' (EnumClassDef | ObjectDef) */
2166-
def enumCase(start: Offset, mods: Modifiers): MemberDef = {
2166+
def enumCase(start: Offset, mods: Modifiers): DefTree = {
21672167
val mods1 = mods.withAddedMod(atPos(in.offset)(Mod.EnumCase())) | Case
21682168
accept(CASE)
21692169
atPos(start, nameStart) {
2170-
val name = ident()
2170+
val id = termIdent()
21712171
if (in.token == LBRACKET || in.token == LPAREN)
2172-
classDefRest(start, mods1, name.toTypeName)
2172+
classDefRest(start, mods1, id.name.toTypeName)
2173+
else if (in.token == COMMA) {
2174+
in.nextToken()
2175+
val ids = commaSeparated(termIdent)
2176+
PatDef(mods1, id :: ids, TypeTree(), EmptyTree)
2177+
}
21732178
else
2174-
objectDefRest(start, mods1, name)
2179+
objectDefRest(start, mods1, id.name.asTermName)
21752180
}
21762181
}
21772182

docs/docs/internals/syntax.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ ObjectDef ::= id TemplateOpt
341341
EnumDef ::= id ClassConstr [`extends' [ConstrApps]] EnumDef(mods, name, tparams, template)
342342
[nl] ‘{’ EnumCaseStat {semi EnumCaseStat} ‘}’
343343
EnumCaseStat ::= {Annotation [nl]} {Modifier} EnumCase
344-
EnumCase ::= `case' (EnumClassDef | ObjectDef)
344+
EnumCase ::= `case' (EnumClassDef | ObjectDef | ids)
345345
EnumClassDef ::= id [ClsTpeParamClause | ClsParamClause] ClassDef(mods, name, tparams, templ)
346346
ClsParamClauses TemplateOpt
347347
TemplateOpt ::= [‘extends’ Template | [nl] TemplateBody]

tests/run/enum-Color.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
enum Color {
2-
case Red
3-
case Green
4-
case Blue
2+
case Red, Green, Blue
53
}
64

75
object Test {

0 commit comments

Comments
 (0)