Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4263,18 +4263,21 @@ object Parsers {
finalizeDef(ModuleDef(name, templ), mods, start)
}

private def checkAccessOnly(mods: Modifiers, where: String): Modifiers =
// We allow `infix to mark the `enum`s type as infix.
// Syntax rules disallow the soft infix modifier on `case`s.
val mods1 = mods & (AccessFlags | Enum | Infix)
if mods1 ne mods then
syntaxError(em"Only access modifiers are allowed on enum $where")
mods1
private def checkAccessOnly(mods: Modifiers, caseStr: String): Modifiers =
// We allow `infix` and `into` on `enum` definitions.
// Syntax rules disallow these soft infix modifiers on `case`s.
val flags = mods.flags
var flags1 = flags
for mod <- mods.mods do
if !mod.flags.isOneOf(AccessFlags | Enum | Infix | Into) then
syntaxError(em"This modifier is not allowed on an enum$caseStr", mod.span)
flags1 = flags1 &~ mod.flags
if flags1 != flags then mods.withFlags(flags1) else mods

/** EnumDef ::= id ClassConstr InheritClauses EnumBody
*/
def enumDef(start: Offset, mods: Modifiers): TypeDef = atSpan(start, nameStart) {
val mods1 = checkAccessOnly(mods, "definitions")
val mods1 = checkAccessOnly(mods, "")
val modulName = ident()
val clsName = modulName.toTypeName
val constr = classConstr(ParamOwner.Class)
Expand All @@ -4285,7 +4288,7 @@ object Parsers {
/** EnumCase = `case' (id ClassConstr [`extends' ConstrApps] | ids)
*/
def enumCase(start: Offset, mods: Modifiers): DefTree = {
val mods1 = checkAccessOnly(mods, "cases") | EnumCase
val mods1 = checkAccessOnly(mods, " case") | EnumCase
accept(CASE)

atSpan(start, nameStart) {
Expand Down
3 changes: 3 additions & 0 deletions docs/_docs/reference/enums/enums.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ The fields referenced by `Mercury` are not visible, and the fields referenced by
be referenced directly (using `import Planet.*`). You must use an indirect reference,
such as demonstrated with `Earth`.

Enum cases accept only access modifiers.
Enum classes accept only access modifiers and `into` or `infix`.

## Deprecation of Enum Cases

As a library author, you may want to signal that an enum case is no longer intended for use. However you could still want to gracefully handle the removal of a case from your public API, such as special casing deprecated cases.
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/i23400.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ case class Baz(foo: MyInto[Foo])

given Conversion[Int, Foo] = Foo(_)

into enum Color: // error
into enum Color: // ok
case Red, Green

def test =
Expand Down
114 changes: 114 additions & 0 deletions tests/neg/i5525.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
-- Error: tests/neg/i5525.scala:1:0 ------------------------------------------------------------------------------------
1 |abstract enum Foo1 { case C } // error: only access modifiers allowed
|^^^^^^^^
|This modifier is not allowed on an enum
-- Error: tests/neg/i5525.scala:2:0 ------------------------------------------------------------------------------------
2 |final enum Foo2 { case C } // error: only access modifiers allowed
|^^^^^
|This modifier is not allowed on an enum
-- Error: tests/neg/i5525.scala:3:0 ------------------------------------------------------------------------------------
3 |sealed enum Foo3 { case C } // error: only access modifiers allowed
|^^^^^^
|This modifier is not allowed on an enum
-- Error: tests/neg/i5525.scala:4:0 ------------------------------------------------------------------------------------
4 |implicit enum Foo4 { case C } // error: only access modifiers allowed
|^^^^^^^^
|This modifier is not allowed on an enum
-- Error: tests/neg/i5525.scala:5:0 ------------------------------------------------------------------------------------
5 |lazy enum Foo5 { case C } // error: only access modifiers allowed
|^^^^
|This modifier is not allowed on an enum
-- Error: tests/neg/i5525.scala:6:0 ------------------------------------------------------------------------------------
6 |override enum Foo7 { case C } // error: only access modifiers allowed
|^^^^^^^^
|This modifier is not allowed on an enum
-- Error: tests/neg/i5525.scala:7:0 ------------------------------------------------------------------------------------
7 |inline enum Foo8 { case C } // error: only access modifiers allowed
|^^^^^^
|This modifier is not allowed on an enum
-- Error: tests/neg/i5525.scala:8:0 ------------------------------------------------------------------------------------
8 |opaque enum Foo9 { case C } // error: only access modifiers allowed
|^^^^^^
|This modifier is not allowed on an enum
-- Error: tests/neg/i5525.scala:11:2 -----------------------------------------------------------------------------------
11 | abstract case C1() // error: only access modifiers allowed
| ^^^^^^^^
| This modifier is not allowed on an enum case
-- Error: tests/neg/i5525.scala:12:2 -----------------------------------------------------------------------------------
12 | final case C2() // error: only access modifiers allowed
| ^^^^^
| This modifier is not allowed on an enum case
-- Error: tests/neg/i5525.scala:13:2 -----------------------------------------------------------------------------------
13 | sealed case C3() // error: only access modifiers allowed
| ^^^^^^
| This modifier is not allowed on an enum case
-- Error: tests/neg/i5525.scala:14:2 -----------------------------------------------------------------------------------
14 | implicit case C4() // error: only access modifiers allowed
| ^^^^^^^^
| This modifier is not allowed on an enum case
-- Error: tests/neg/i5525.scala:15:2 -----------------------------------------------------------------------------------
15 | lazy case C5() // error: only access modifiers allowed
| ^^^^
| This modifier is not allowed on an enum case
-- Error: tests/neg/i5525.scala:16:2 -----------------------------------------------------------------------------------
16 | override case C7() // error: only access modifiers allowed
| ^^^^^^^^
| This modifier is not allowed on an enum case
-- Error: tests/neg/i5525.scala:22:2 -----------------------------------------------------------------------------------
22 | abstract case C1 // error: only access modifiers allowed
| ^^^^^^^^
| This modifier is not allowed on an enum case
-- Error: tests/neg/i5525.scala:23:2 -----------------------------------------------------------------------------------
23 | final case C2 // error: only access modifiers allowed
| ^^^^^
| This modifier is not allowed on an enum case
-- Error: tests/neg/i5525.scala:24:2 -----------------------------------------------------------------------------------
24 | sealed case C3 // error: only access modifiers allowed
| ^^^^^^
| This modifier is not allowed on an enum case
-- Error: tests/neg/i5525.scala:25:2 -----------------------------------------------------------------------------------
25 | implicit case C4 // error: only access modifiers allowed
| ^^^^^^^^
| This modifier is not allowed on an enum case
-- Error: tests/neg/i5525.scala:26:2 -----------------------------------------------------------------------------------
26 | lazy case C5 // error: only access modifiers allowed
| ^^^^
| This modifier is not allowed on an enum case
-- Error: tests/neg/i5525.scala:27:2 -----------------------------------------------------------------------------------
27 | override case C7 // error: only access modifiers allowed
| ^^^^^^^^
| This modifier is not allowed on an enum case
-- Error: tests/neg/i5525.scala:33:12 ----------------------------------------------------------------------------------
33 | inline case C10() // error: only access modifiers allowed
| ^^^^
| end of statement expected but 'case' found
-- Error: tests/neg/i5525.scala:36:0 -----------------------------------------------------------------------------------
36 |final enum Foo13 { // error: only access modifiers and `into` allowed
|^^^^^
|This modifier is not allowed on an enum
-- Error: tests/neg/i5525.scala:42:8 -----------------------------------------------------------------------------------
42 | infix case C2 extends Foo14[Int, Int] // error // error
| ^^^^
| end of statement expected but 'case' found
-- Error: tests/neg/i5525.scala:49:7 -----------------------------------------------------------------------------------
49 | into case C1 // error
| ^^^^
| end of statement expected but 'case' found
-- [E145] Syntax Error: tests/neg/i5525.scala:32:5 ---------------------------------------------------------------------
32 |enum Foo12 { // error: Enumerations must contain at least one case
| ^^^^^
| Enumerations must contain at least one case
|
| longer explanation available when compiling with `-explain`
-- [E006] Not Found Error: tests/neg/i5525.scala:42:2 ------------------------------------------------------------------
42 | infix case C2 extends Foo14[Int, Int] // error // error
| ^^^^^
| Not found: infix
|
| longer explanation available when compiling with `-explain`
-- [E129] Potential Issue Warning: tests/neg/i5525.scala:49:2 ----------------------------------------------------------
49 | into case C1 // error
| ^^^^
| A pure expression does nothing in statement position
|
| longer explanation available when compiling with `-explain`
32 changes: 24 additions & 8 deletions tests/neg/i5525.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
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
override enum Foo7 {} // error: only access modifiers allowed
inline enum Foo8 {} // error: only access modifiers allowed
opaque enum Foo9 {} // error: only access modifiers allowed
abstract enum Foo1 { case C } // error: only access modifiers allowed
final enum Foo2 { case C } // error: only access modifiers allowed
sealed enum Foo3 { case C } // error: only access modifiers allowed
implicit enum Foo4 { case C } // error: only access modifiers allowed
lazy enum Foo5 { case C } // error: only access modifiers allowed
override enum Foo7 { case C } // error: only access modifiers allowed
inline enum Foo8 { case C } // error: only access modifiers allowed
opaque enum Foo9 { case C } // error: only access modifiers allowed

enum Foo10 {
abstract case C1() // error: only access modifiers allowed
Expand All @@ -31,4 +31,20 @@ enum Foo11 {

enum Foo12 { // error: Enumerations must contain at least one case
inline case C10() // error: only access modifiers allowed
}

final enum Foo13 { // error: only access modifiers and `into` allowed
case C1
}

infix enum Foo14[A, B]{ // OK
case C1 extends Foo14[Int, Int]
infix case C2 extends Foo14[Int, Int] // error // error
}

import language.experimental.into

into enum Foo15 { // OK
case C0
into case C1 // error
}
2 changes: 1 addition & 1 deletion tests/neg/i5525b.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//> using options -language:experimental.erasedDefinitions

erased enum Foo6 {} // error: only access modifiers allowed
erased enum Foo6 { case C } // error: only access modifiers allowed

enum Foo10 { // error: Enumerations must contain at least one case
erased case C6() // error // error
Expand Down
5 changes: 5 additions & 0 deletions tests/pos/infix-enum.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
infix enum Foo[A, B]:
case C1 extends Foo[Int, Int]

val x: Int Foo Int = Foo.C1

Loading