diff options
-rw-r--r-- | compiler/src/dotty/tools/dotc/ast/Desugar.scala | 18 | ||||
-rw-r--r-- | compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala | 35 | ||||
-rw-r--r-- | compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 19 | ||||
-rw-r--r-- | docs/docs/internals/syntax.md | 2 | ||||
-rw-r--r-- | tests/run/enum-Color.scala | 4 |
5 files changed, 48 insertions, 30 deletions
diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 575af97f4..04834b04b 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -576,11 +576,23 @@ object desugar { /** val p1, ..., pN: T = E * ==> * makePatDef[[val p1: T1 = E]]; ...; makePatDef[[val pN: TN = E]] + * + * case e1, ..., eN + * ==> + * expandSimpleEnumCase([case e1]); ...; expandSimpleEnumCase([case eN]) */ - def patDef(pdef: PatDef)(implicit ctx: Context): Tree = { + def patDef(pdef: PatDef)(implicit ctx: Context): Tree = flatTree { val PatDef(mods, pats, tpt, rhs) = pdef - val pats1 = if (tpt.isEmpty) pats else pats map (Typed(_, tpt)) - flatTree(pats1 map (makePatDef(pdef, mods, _, rhs))) + if (mods.hasMod[Mod.EnumCase] && enumCaseIsLegal(pdef)) + pats map { + case id: Ident => + expandSimpleEnumCase(id.name.asTermName, mods, + Position(pdef.pos.start, id.pos.end, id.pos.start)) + } + else { + val pats1 = if (tpt.isEmpty) pats else pats map (Typed(_, tpt)) + pats1 map (makePatDef(pdef, mods, _, rhs)) + } } /** If `pat` is a variable pattern, diff --git a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala index 8bd3c8580..7fdff0e2d 100644 --- a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala +++ b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala @@ -24,14 +24,15 @@ object DesugarEnums { result } - def isLegalEnumCase(tree: MemberDef)(implicit ctx: Context): Boolean = { - tree.mods.hasMod[Mod.EnumCase] && - ( ctx.owner.is(ModuleClass) && enumClass.derivesFrom(defn.EnumClass) + def isLegalEnumCase(tree: MemberDef)(implicit ctx: Context): Boolean = + tree.mods.hasMod[Mod.EnumCase] && enumCaseIsLegal(tree) + + def enumCaseIsLegal(tree: Tree)(implicit ctx: Context): Boolean = ( + ctx.owner.is(ModuleClass) && enumClass.derivesFrom(defn.EnumClass) || { ctx.error(em"case not allowed here, since owner ${ctx.owner} is not an `enum' object", tree.pos) false } ) - } /** Type parameters reconstituted from the constructor * of the `enum' class corresponding to an enum case. @@ -104,23 +105,25 @@ object DesugarEnums { List(privateValuesDef, valueOfDef, withNameDef, valuesDef, newDef) } - def expandEnumModule(name: TermName, impl: Template, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree = { - def nameLit = Literal(Constant(name.toString)) - if (impl.parents.isEmpty) { - if (reconstitutedEnumTypeParams(pos).nonEmpty) - ctx.error(i"illegal enum value of generic $enumClass: an explicit `extends' clause is needed", pos) - val tag = nextEnumTag - val prefix = if (tag == 0) enumScaffolding else Nil - val creator = Apply(Ident(nme.DOLLAR_NEW), List(Literal(Constant(tag)), nameLit)) - val vdef = ValDef(name, enumClassRef, creator).withMods(mods | Final).withPos(pos) - flatTree(prefix ::: vdef :: Nil).withPos(pos.startPos) - } else { + def expandEnumModule(name: TermName, impl: Template, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree = + if (impl.parents.isEmpty) + expandSimpleEnumCase(name, mods, pos) + else { def toStringMeth = - DefDef(nme.toString_, Nil, Nil, TypeTree(defn.StringType), nameLit) + DefDef(nme.toString_, Nil, Nil, TypeTree(defn.StringType), Literal(Constant(name.toString))) .withFlags(Override) val impl1 = cpy.Template(impl)(body = impl.body ++ List(enumTagMeth, toStringMeth)) ValDef(name, TypeTree(), New(impl1)).withMods(mods | Final).withPos(pos) } + + def expandSimpleEnumCase(name: TermName, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree = { + if (reconstitutedEnumTypeParams(pos).nonEmpty) + ctx.error(i"illegal enum value of generic $enumClass: an explicit `extends' clause is needed", pos) + val tag = nextEnumTag + val prefix = if (tag == 0) enumScaffolding else Nil + val creator = Apply(Ident(nme.DOLLAR_NEW), List(Literal(Constant(tag)), Literal(Constant(name.toString)))) + val vdef = ValDef(name, enumClassRef, creator).withMods(mods | Final).withPos(pos) + flatTree(prefix ::: vdef :: Nil).withPos(pos.startPos) } } diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index ee736179a..9864281a5 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -2149,8 +2149,8 @@ object Parsers { } /** EnumCaseStats = EnumCaseStat {semi EnumCaseStat */ - def enumCaseStats(): List[MemberDef] = { - val cases = new ListBuffer[MemberDef] += enumCaseStat() + def enumCaseStats(): List[DefTree] = { + val cases = new ListBuffer[DefTree] += enumCaseStat() while (in.token != RBRACE) { acceptStatSep() cases += enumCaseStat() @@ -2159,19 +2159,24 @@ object Parsers { } /** EnumCaseStat = {Annotation [nl]} {Modifier} EnumCase */ - def enumCaseStat(): MemberDef = + def enumCaseStat(): DefTree = enumCase(in.offset, defAnnotsMods(modifierTokens)) /** EnumCase = `case' (EnumClassDef | ObjectDef) */ - def enumCase(start: Offset, mods: Modifiers): MemberDef = { + def enumCase(start: Offset, mods: Modifiers): DefTree = { val mods1 = mods.withAddedMod(atPos(in.offset)(Mod.EnumCase())) | Case accept(CASE) atPos(start, nameStart) { - val name = ident() + val id = termIdent() if (in.token == LBRACKET || in.token == LPAREN) - classDefRest(start, mods1, name.toTypeName) + classDefRest(start, mods1, id.name.toTypeName) + else if (in.token == COMMA) { + in.nextToken() + val ids = commaSeparated(termIdent) + PatDef(mods1, id :: ids, TypeTree(), EmptyTree) + } else - objectDefRest(start, mods1, name) + objectDefRest(start, mods1, id.name.asTermName) } } diff --git a/docs/docs/internals/syntax.md b/docs/docs/internals/syntax.md index c7f282dc1..e4285e20f 100644 --- a/docs/docs/internals/syntax.md +++ b/docs/docs/internals/syntax.md @@ -341,7 +341,7 @@ ObjectDef ::= id TemplateOpt EnumDef ::= id ClassConstr [`extends' [ConstrApps]] EnumDef(mods, name, tparams, template) [nl] ‘{’ EnumCaseStat {semi EnumCaseStat} ‘}’ EnumCaseStat ::= {Annotation [nl]} {Modifier} EnumCase -EnumCase ::= `case' (EnumClassDef | ObjectDef) +EnumCase ::= `case' (EnumClassDef | ObjectDef | ids) EnumClassDef ::= id [ClsTpeParamClause | ClsParamClause] ClassDef(mods, name, tparams, templ) ClsParamClauses TemplateOpt TemplateOpt ::= [‘extends’ Template | [nl] TemplateBody] diff --git a/tests/run/enum-Color.scala b/tests/run/enum-Color.scala index 24916abee..1a077bf8e 100644 --- a/tests/run/enum-Color.scala +++ b/tests/run/enum-Color.scala @@ -1,7 +1,5 @@ enum Color { - case Red - case Green - case Blue + case Red, Green, Blue } object Test { |