Skip to content

Commit 79020c7

Browse files
committed
Forbid inheriting from Scala enums altogether
1 parent 4670733 commit 79020c7

File tree

4 files changed

+16
-33
lines changed

4 files changed

+16
-33
lines changed

compiler/src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -846,14 +846,21 @@ trait Checking {
846846
}
847847

848848
/** Check that all case classes that extend `scala.Enum` are `enum` cases */
849-
def checkEnum(cdef: untpd.TypeDef, cls: Symbol)(implicit ctx: Context): Unit = {
849+
def checkEnum(cdef: untpd.TypeDef, cls: Symbol, firstParent: Symbol)(implicit ctx: Context): Unit = {
850850
import untpd.modsDeco
851851
def isEnumAnonCls =
852852
cls.isAnonymousClass &&
853853
cls.owner.isTerm &&
854854
(cls.owner.flagsUNSAFE.is(Case) || cls.owner.name == nme.DOLLAR_NEW)
855-
if (!cdef.mods.isEnumCase && !isEnumAnonCls)
856-
ctx.error(em"normal case $cls in ${cls.owner} cannot extend an enum", cdef.pos)
855+
if (!cdef.mods.isEnumCase && !isEnumAnonCls) {
856+
if (cls.is(Case))
857+
ctx.error(em"normal case $cls in ${cls.owner} cannot extend an enum", cdef.pos)
858+
else if (firstParent != defn.EnumClass && firstParent.derivesFrom(defn.EnumClass) && !cdef.mods.isEnumCase && !isEnumAnonCls)
859+
// Since enums are classes and Namer checks that classes don't extend multiple classes, we only check the class
860+
// parent.
861+
//Tricky to phrase; language taken from "case-to-case inheritance is prohibited".
862+
ctx.error(s"${cls.name} has enum ancestor ${firstParent.name}, but inheriting from enums is prohibited", cdef.pos)
863+
}
857864
}
858865

859866
/** Check that all references coming from enum cases in an enum companion object
@@ -931,7 +938,7 @@ trait Checking {
931938

932939
trait ReChecking extends Checking {
933940
import tpd._
934-
override def checkEnum(cdef: untpd.TypeDef, cls: Symbol)(implicit ctx: Context): Unit = ()
941+
override def checkEnum(cdef: untpd.TypeDef, cls: Symbol, firstParent: Symbol)(implicit ctx: Context): Unit = ()
935942
override def checkRefsLegal(tree: tpd.Tree, badOwner: Symbol, allowed: (Name, Symbol) => Boolean, where: String)(implicit ctx: Context): Unit = ()
936943
override def checkEnumCompanions(stats: List[Tree], enumContexts: collection.Map[Symbol, Context])(implicit ctx: Context): List[Tree] = stats
937944
}

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,15 +1574,8 @@ class Typer extends Namer
15741574
.withType(dummy.termRef)
15751575
if (!cls.is(AbstractOrTrait) && !ctx.isAfterTyper)
15761576
checkRealizableBounds(cls, cdef.namePos)
1577-
if (cls.is(Case) && cls.derivesFrom(defn.EnumClass)) checkEnum(cdef, cls)
1578-
if (seenParents.contains(defn.EnumClass)) {
1579-
// Since enums are classes and Namer checks that classes don't extend multiple classes, we only check the class
1580-
// parent.
1581-
val firstParent = parents1.head.tpe.dealias.typeSymbol
1582-
if (firstParent.derivesFrom(defn.EnumClass))
1583-
//Tricky to phrase; language taken from "case-to-case inheritance is prohibited".
1584-
ctx.error(s"Enum ${cls.name} has enum ancestor ${firstParent.name}, but enum-to-enum inheritance is prohibited", cdef.pos)
1585-
}
1577+
val firstParent = parents1.head.tpe.dealias.typeSymbol
1578+
if (cls.derivesFrom(defn.EnumClass)) checkEnum(cdef, cls, firstParent)
15861579

15871580
val cdef1 = assignType(cpy.TypeDef(cdef)(name, impl1), cls)
15881581
checkVariance(cdef1)

tests/neg/i5008.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@ enum Bar { case A }
33
enum Baz extends Foo { case Z } // error
44

55
enum Quux extends Foo with Bar { case Z } // error
6+
7+
class Quuw extends Foo // error
8+
class Quuz extends Foo { val enumTag = 1 } // error

tests/pos/enum-List-control.scala

Lines changed: 0 additions & 20 deletions
This file was deleted.

0 commit comments

Comments
 (0)