diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 7d5b9f4c741a..39a8b7350ba0 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -253,6 +253,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion)(inlineContext(call))) case templ: Template => withNoCheckNews(templ.parents.flatMap(newPart)) { + Checking.checkEnumParentOK(templ.symbol.owner) forwardParamAccessors(templ) synthMbr.addSyntheticMembers( superAcc.wrapTemplate(templ)( diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index f94370bc7803..bbda0d6a112c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -592,6 +592,17 @@ object Checking { stats.foreach(checkValueClassMember) } } + + /** Check that an enum case extends its enum class */ + def checkEnumParentOK(cls: Symbol)(using ctx: Context): Unit = + val enumCase = + if cls.isAllOf(EnumCase) then cls + else if cls.isAnonymousClass && cls.owner.isAllOf(EnumCase) then cls.owner + else NoSymbol + if enumCase.exists then + val enumCls = enumCase.owner.linkedClass + if !cls.info.parents.exists(_.typeSymbol == enumCls) then + ctx.error(i"enum case does not extend its enum $enumCls", enumCase.sourcePos) } trait Checking { diff --git a/docs/docs/internals/syntax.md b/docs/docs/internals/syntax.md index ee59cab8d50f..c8434db96410 100644 --- a/docs/docs/internals/syntax.md +++ b/docs/docs/internals/syntax.md @@ -105,7 +105,7 @@ yield ``` as derives extension inline on opaque open using -~ * | & + - +* + - ``` ## Context-free Syntax diff --git a/docs/docs/reference/enums/desugarEnums.md b/docs/docs/reference/enums/desugarEnums.md index 0041a5db00be..b8826717907e 100644 --- a/docs/docs/reference/enums/desugarEnums.md +++ b/docs/docs/reference/enums/desugarEnums.md @@ -196,6 +196,9 @@ Cases such as `case C` expand to a `@static val` as opposed to a `val`. This all ### Other Rules -A normal case class which is not produced from an enum case is not allowed to extend + - A normal case class which is not produced from an enum case is not allowed to extend `scala.Enum`. This ensures that the only cases of an enum are the ones that are explicitly declared in it. + + - If an enum case has an extends clause, the enum class must be one of the + classes that's extended. \ No newline at end of file diff --git a/tests/neg/i6601.scala b/tests/neg/i6601.scala new file mode 100644 index 000000000000..2f167288ae31 --- /dev/null +++ b/tests/neg/i6601.scala @@ -0,0 +1,10 @@ +object GADTs2 { + enum Var[G, A] { + case Z[A, G]() extends Expr[(A, G), A] // error + case X extends AnyRef // error + } + enum Expr[G, A] { + case Lit[G](n: Int) extends Expr[G, Int] + // case S[A, G](x: + } +} \ No newline at end of file