Skip to content

Commit 658c8bd

Browse files
authored
Allow into on enums (#23795)
2 parents 9e88707 + 8005ac3 commit 658c8bd

File tree

7 files changed

+160
-19
lines changed

7 files changed

+160
-19
lines changed

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

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4263,18 +4263,21 @@ object Parsers {
42634263
finalizeDef(ModuleDef(name, templ), mods, start)
42644264
}
42654265

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

42744277
/** EnumDef ::= id ClassConstr InheritClauses EnumBody
42754278
*/
42764279
def enumDef(start: Offset, mods: Modifiers): TypeDef = atSpan(start, nameStart) {
4277-
val mods1 = checkAccessOnly(mods, "definitions")
4280+
val mods1 = checkAccessOnly(mods, "")
42784281
val modulName = ident()
42794282
val clsName = modulName.toTypeName
42804283
val constr = classConstr(ParamOwner.Class)
@@ -4285,7 +4288,7 @@ object Parsers {
42854288
/** EnumCase = `case' (id ClassConstr [`extends' ConstrApps] | ids)
42864289
*/
42874290
def enumCase(start: Offset, mods: Modifiers): DefTree = {
4288-
val mods1 = checkAccessOnly(mods, "cases") | EnumCase
4291+
val mods1 = checkAccessOnly(mods, " case") | EnumCase
42894292
accept(CASE)
42904293

42914294
atSpan(start, nameStart) {

docs/_docs/reference/enums/enums.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ The fields referenced by `Mercury` are not visible, and the fields referenced by
117117
be referenced directly (using `import Planet.*`). You must use an indirect reference,
118118
such as demonstrated with `Earth`.
119119

120+
Enum cases accept only access modifiers.
121+
Enum classes accept only access modifiers and `into` or `infix`.
122+
120123
## Deprecation of Enum Cases
121124

122125
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.

tests/neg/i23400.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ case class Baz(foo: MyInto[Foo])
1414

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

17-
into enum Color: // error
17+
into enum Color: // ok
1818
case Red, Green
1919

2020
def test =

tests/neg/i5525.check

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
-- Error: tests/neg/i5525.scala:1:0 ------------------------------------------------------------------------------------
2+
1 |abstract enum Foo1 { case C } // error: only access modifiers allowed
3+
|^^^^^^^^
4+
|This modifier is not allowed on an enum
5+
-- Error: tests/neg/i5525.scala:2:0 ------------------------------------------------------------------------------------
6+
2 |final enum Foo2 { case C } // error: only access modifiers allowed
7+
|^^^^^
8+
|This modifier is not allowed on an enum
9+
-- Error: tests/neg/i5525.scala:3:0 ------------------------------------------------------------------------------------
10+
3 |sealed enum Foo3 { case C } // error: only access modifiers allowed
11+
|^^^^^^
12+
|This modifier is not allowed on an enum
13+
-- Error: tests/neg/i5525.scala:4:0 ------------------------------------------------------------------------------------
14+
4 |implicit enum Foo4 { case C } // error: only access modifiers allowed
15+
|^^^^^^^^
16+
|This modifier is not allowed on an enum
17+
-- Error: tests/neg/i5525.scala:5:0 ------------------------------------------------------------------------------------
18+
5 |lazy enum Foo5 { case C } // error: only access modifiers allowed
19+
|^^^^
20+
|This modifier is not allowed on an enum
21+
-- Error: tests/neg/i5525.scala:6:0 ------------------------------------------------------------------------------------
22+
6 |override enum Foo7 { case C } // error: only access modifiers allowed
23+
|^^^^^^^^
24+
|This modifier is not allowed on an enum
25+
-- Error: tests/neg/i5525.scala:7:0 ------------------------------------------------------------------------------------
26+
7 |inline enum Foo8 { case C } // error: only access modifiers allowed
27+
|^^^^^^
28+
|This modifier is not allowed on an enum
29+
-- Error: tests/neg/i5525.scala:8:0 ------------------------------------------------------------------------------------
30+
8 |opaque enum Foo9 { case C } // error: only access modifiers allowed
31+
|^^^^^^
32+
|This modifier is not allowed on an enum
33+
-- Error: tests/neg/i5525.scala:11:2 -----------------------------------------------------------------------------------
34+
11 | abstract case C1() // error: only access modifiers allowed
35+
| ^^^^^^^^
36+
| This modifier is not allowed on an enum case
37+
-- Error: tests/neg/i5525.scala:12:2 -----------------------------------------------------------------------------------
38+
12 | final case C2() // error: only access modifiers allowed
39+
| ^^^^^
40+
| This modifier is not allowed on an enum case
41+
-- Error: tests/neg/i5525.scala:13:2 -----------------------------------------------------------------------------------
42+
13 | sealed case C3() // error: only access modifiers allowed
43+
| ^^^^^^
44+
| This modifier is not allowed on an enum case
45+
-- Error: tests/neg/i5525.scala:14:2 -----------------------------------------------------------------------------------
46+
14 | implicit case C4() // error: only access modifiers allowed
47+
| ^^^^^^^^
48+
| This modifier is not allowed on an enum case
49+
-- Error: tests/neg/i5525.scala:15:2 -----------------------------------------------------------------------------------
50+
15 | lazy case C5() // error: only access modifiers allowed
51+
| ^^^^
52+
| This modifier is not allowed on an enum case
53+
-- Error: tests/neg/i5525.scala:16:2 -----------------------------------------------------------------------------------
54+
16 | override case C7() // error: only access modifiers allowed
55+
| ^^^^^^^^
56+
| This modifier is not allowed on an enum case
57+
-- Error: tests/neg/i5525.scala:22:2 -----------------------------------------------------------------------------------
58+
22 | abstract case C1 // error: only access modifiers allowed
59+
| ^^^^^^^^
60+
| This modifier is not allowed on an enum case
61+
-- Error: tests/neg/i5525.scala:23:2 -----------------------------------------------------------------------------------
62+
23 | final case C2 // error: only access modifiers allowed
63+
| ^^^^^
64+
| This modifier is not allowed on an enum case
65+
-- Error: tests/neg/i5525.scala:24:2 -----------------------------------------------------------------------------------
66+
24 | sealed case C3 // error: only access modifiers allowed
67+
| ^^^^^^
68+
| This modifier is not allowed on an enum case
69+
-- Error: tests/neg/i5525.scala:25:2 -----------------------------------------------------------------------------------
70+
25 | implicit case C4 // error: only access modifiers allowed
71+
| ^^^^^^^^
72+
| This modifier is not allowed on an enum case
73+
-- Error: tests/neg/i5525.scala:26:2 -----------------------------------------------------------------------------------
74+
26 | lazy case C5 // error: only access modifiers allowed
75+
| ^^^^
76+
| This modifier is not allowed on an enum case
77+
-- Error: tests/neg/i5525.scala:27:2 -----------------------------------------------------------------------------------
78+
27 | override case C7 // error: only access modifiers allowed
79+
| ^^^^^^^^
80+
| This modifier is not allowed on an enum case
81+
-- Error: tests/neg/i5525.scala:33:12 ----------------------------------------------------------------------------------
82+
33 | inline case C10() // error: only access modifiers allowed
83+
| ^^^^
84+
| end of statement expected but 'case' found
85+
-- Error: tests/neg/i5525.scala:36:0 -----------------------------------------------------------------------------------
86+
36 |final enum Foo13 { // error: only access modifiers and `into` allowed
87+
|^^^^^
88+
|This modifier is not allowed on an enum
89+
-- Error: tests/neg/i5525.scala:42:8 -----------------------------------------------------------------------------------
90+
42 | infix case C2 extends Foo14[Int, Int] // error // error
91+
| ^^^^
92+
| end of statement expected but 'case' found
93+
-- Error: tests/neg/i5525.scala:49:7 -----------------------------------------------------------------------------------
94+
49 | into case C1 // error
95+
| ^^^^
96+
| end of statement expected but 'case' found
97+
-- [E145] Syntax Error: tests/neg/i5525.scala:32:5 ---------------------------------------------------------------------
98+
32 |enum Foo12 { // error: Enumerations must contain at least one case
99+
| ^^^^^
100+
| Enumerations must contain at least one case
101+
|
102+
| longer explanation available when compiling with `-explain`
103+
-- [E006] Not Found Error: tests/neg/i5525.scala:42:2 ------------------------------------------------------------------
104+
42 | infix case C2 extends Foo14[Int, Int] // error // error
105+
| ^^^^^
106+
| Not found: infix
107+
|
108+
| longer explanation available when compiling with `-explain`
109+
-- [E129] Potential Issue Warning: tests/neg/i5525.scala:49:2 ----------------------------------------------------------
110+
49 | into case C1 // error
111+
| ^^^^
112+
| A pure expression does nothing in statement position
113+
|
114+
| longer explanation available when compiling with `-explain`

tests/neg/i5525.scala

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
abstract enum Foo1 {} // error: only access modifiers allowed
2-
final enum Foo2 {} // error: only access modifiers allowed
3-
sealed enum Foo3 {} // error: only access modifiers allowed
4-
implicit enum Foo4 {} // error: only access modifiers allowed
5-
lazy enum Foo5 {} // error: only access modifiers allowed
6-
override enum Foo7 {} // error: only access modifiers allowed
7-
inline enum Foo8 {} // error: only access modifiers allowed
8-
opaque enum Foo9 {} // error: only access modifiers allowed
1+
abstract enum Foo1 { case C } // error: only access modifiers allowed
2+
final enum Foo2 { case C } // error: only access modifiers allowed
3+
sealed enum Foo3 { case C } // error: only access modifiers allowed
4+
implicit enum Foo4 { case C } // error: only access modifiers allowed
5+
lazy enum Foo5 { case C } // error: only access modifiers allowed
6+
override enum Foo7 { case C } // error: only access modifiers allowed
7+
inline enum Foo8 { case C } // error: only access modifiers allowed
8+
opaque enum Foo9 { case C } // error: only access modifiers allowed
99

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

3232
enum Foo12 { // error: Enumerations must contain at least one case
3333
inline case C10() // error: only access modifiers allowed
34+
}
35+
36+
final enum Foo13 { // error: only access modifiers and `into` allowed
37+
case C1
38+
}
39+
40+
infix enum Foo14[A, B]{ // OK
41+
case C1 extends Foo14[Int, Int]
42+
infix case C2 extends Foo14[Int, Int] // error // error
43+
}
44+
45+
import language.experimental.into
46+
47+
into enum Foo15 { // OK
48+
case C0
49+
into case C1 // error
3450
}

tests/neg/i5525b.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//> using options -language:experimental.erasedDefinitions
22

3-
erased enum Foo6 {} // error: only access modifiers allowed
3+
erased enum Foo6 { case C } // error: only access modifiers allowed
44

55
enum Foo10 { // error: Enumerations must contain at least one case
66
erased case C6() // error // error

tests/pos/infix-enum.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
infix enum Foo[A, B]:
2+
case C1 extends Foo[Int, Int]
3+
4+
val x: Int Foo Int = Foo.C1
5+

0 commit comments

Comments
 (0)