diff --git a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala index 69b0bf780b75..335bdad749c5 100644 --- a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala +++ b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala @@ -69,8 +69,8 @@ object DesugarEnums { /** Add implied flags to an enum class or an enum case */ def addEnumFlags(cdef: TypeDef)(implicit ctx: Context): TypeDef = - if (cdef.mods.isEnumClass) cdef.withMods(cdef.mods.withFlags(cdef.mods.flags | Abstract | Sealed)) - else if (isEnumCase(cdef)) cdef.withMods(cdef.mods.withFlags(cdef.mods.flags | Final)) + if (cdef.mods.isEnumClass) cdef.withMods(cdef.mods.toTypeFlags | Abstract | Sealed) + else if (isEnumCase(cdef)) cdef.withMods(cdef.mods | Final) else cdef private def valuesDot(name: String) = Select(Ident(nme.DOLLAR_VALUES), name.toTermName) diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala index 6d23884b0d32..6fd02deb9786 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -131,8 +131,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { case class Lazy() extends Mod(Flags.Lazy) case class Inline() extends Mod(Flags.Inline) - - case class Enum() extends Mod(Flags.Enum) } /** Modifiers and annotations for definitions diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 70541b54857b..6116c42594d9 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -2341,7 +2341,7 @@ object Parsers { case CASEOBJECT => objectDef(start, posMods(start, mods | Case | Module)) case ENUM => - enumDef(start, mods, atPos(in.skipToken()) { Mod.Enum() }) + enumDef(start, posMods(start, mods | Enum)) case _ => syntaxErrorOrIncomplete(ExpectedStartOfTopLevelDefinition()) EmptyTree @@ -2387,18 +2387,26 @@ object Parsers { /** EnumDef ::= id ClassConstr [`extends' [ConstrApps]] EnumBody */ - def enumDef(start: Offset, mods: Modifiers, enumMod: Mod): TypeDef = atPos(start, nameStart) { + def enumDef(start: Offset, mods: Modifiers): TypeDef = atPos(start, nameStart) { + val InvalidEnumClassModifiers = ModifierFlags &~ (Private | Protected) + if (mods.is(InvalidEnumClassModifiers)) + syntaxError("Only access modifiers are allowed on enum definitions", mods.pos) + + val mods1 = mods &~ InvalidEnumClassModifiers val modName = ident() val clsName = modName.toTypeName val constr = classConstr(clsName) val impl = templateOpt(constr, isEnum = true) - TypeDef(clsName, impl).withMods(addMod(mods, enumMod)).setComment(in.getDocComment(start)) + TypeDef(clsName, impl).withMods(mods1).setComment(in.getDocComment(start)) } /** EnumCase = `case' (id ClassConstr [`extends' ConstrApps] | ids) */ def enumCase(start: Offset, mods: Modifiers): DefTree = { - val mods1 = addMod(mods, atPos(in.offset)(Mod.Enum())) | Case + if (mods.is(ModifierFlags)) + syntaxError("Modifiers are not allowed on enum cases", mods.pos) + + val mods1 = mods &~ ModifierFlags | EnumCase accept(CASE) in.adjustSepRegions(ARROW) diff --git a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala index b9afcf03aa71..f513bda0e061 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala @@ -236,7 +236,7 @@ object Tokens extends TokensCommon { final val modifierTokensOrCase: TokenSet = modifierTokens | BitSet(CASE) - final val modifierFollowers = modifierTokens | defIntroTokens + final val modifierFollowers = modifierTokensOrCase | defIntroTokens /** Is token only legal as start of statement (eof also included)? */ final val mustStartStatTokens: TokenSet = defIntroTokens | modifierTokens | BitSet(IMPORT, PACKAGE) diff --git a/tests/neg/i5495.scala b/tests/neg/i5495.scala new file mode 100644 index 000000000000..72f1e88cd1b1 --- /dev/null +++ b/tests/neg/i5495.scala @@ -0,0 +1,37 @@ +abstract enum Foo1 {} // error: only access modifiers allowed +final enum Foo2 {} // error: only access modifiers allowed +sealed enum Foo3 {} // error: only access modifiers allowed +implicit enum Foo4 {} // error: only access modifiers allowed +lazy enum Foo5 {} // error: only access modifiers allowed +erased enum Foo6 {} // error: only access modifiers allowed +override enum Foo7 {} // error: only access modifiers allowed +inline enum Foo8 {} // error: only access modifiers allowed +opaque enum Foo9 {} // error: only access modifiers allowed + +enum Foo10 { + abstract case C1() // error: no modifier allowed + final case C2() // error: no modifier allowed + sealed case C3() // error: no modifier allowed + implicit case C4() // error: no modifier allowed + lazy case C5() // error: no modifier allowed + erased case C6() // error: no modifier allowed + override case C7() // error: no modifier allowed + private case C8() // error: no modifier allowed + protected case C9() // error: no modifier allowed + inline case C10() // error: no modifier allowed + opaque case C11() // error: no modifier allowed +} + +enum Foo11 { + abstract case C1 // error: no modifier allowed + final case C2 // error: no modifier allowed + sealed case C3 // error: no modifier allowed + implicit case C4 // error: no modifier allowed + lazy case C5 // error: no modifier allowed + erased case C6 // error: no modifier allowed + override case C7 // error: no modifier allowed + private case C8 // error: no modifier allowed + protected case C9 // error: no modifier allowed + inline case C10 // error: no modifier allowed + opaque case C11 // error: no modifier allowed +} diff --git a/tests/pos/i2906.scala b/tests/pos/i2906.scala index 1de3937ddb93..ae52a0a66ecc 100644 --- a/tests/pos/i2906.scala +++ b/tests/pos/i2906.scala @@ -1,6 +1,5 @@ enum Foo { case A - private case B - @deprecated("Will be removed") case C - @deprecated("Will be removed") private case D + @deprecated("Will be removed") case B + @deprecated("Will be removed") @volatile case C }