Skip to content

Commit 70e1fed

Browse files
committed
change checking: now add missing enum parent to class
an error is reported when an enum does not have a parent the missing enum class is then added as a parent with appropriate type arguments. The body of the enum implementation class will now always be typechecked
1 parent 421d8c3 commit 70e1fed

File tree

4 files changed

+27
-18
lines changed

4 files changed

+27
-18
lines changed

compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ object DesugarEnums {
9292
* }
9393
*/
9494
private def enumScaffolding(using Context): List[Tree] = {
95-
import dotty.tools.dotc.transform.SymUtils._
9695
val rawEnumClassRef = rawRef(enumClass.typeRef)
9796
extension (tpe: NamedType) def ofRawEnum = AppliedTypeTree(ref(tpe), rawEnumClassRef)
9897
val valuesDef =

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

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,21 +1101,31 @@ trait Checking {
11011101
report.error(ClassCannotExtendEnum(cls, firstParent), cdef.sourcePos)
11021102
}
11031103

1104-
/** Check that the firstParent derives from the declaring enum class.
1104+
/** Check that the firstParent derives from the declaring enum class, if not, adds it as a parent after emitting an
1105+
* error.
11051106
*/
1106-
def checkEnumParent(cls: Symbol, firstParent: Symbol)(using Context): Boolean = {
1107+
def checkEnumParent(cls: Symbol, firstParent: Symbol)(using Context): Unit =
1108+
1109+
extension (sym: Symbol) def typeRefApplied(using Context): Type =
1110+
typeRef.appliedTo(typeParams.map(_.info.loBound))
1111+
1112+
def ensureParentDerivesFrom(enumCase: Symbol)(using Context) =
1113+
val enumCls = enumCase.owner.linkedClass
1114+
if !firstParent.derivesFrom(enumCls) then
1115+
report.error(i"enum case does not extend its enum $enumCls", enumCase.sourcePos)
1116+
cls.info match
1117+
case info: ClassInfo =>
1118+
cls.info = info.derivedClassInfo(classParents = enumCls.typeRefApplied :: info.classParents)
1119+
case _ =>
1120+
11071121
val enumCase =
11081122
if cls.isAllOf(EnumCase) then cls
11091123
else if cls.isAnonymousClass && cls.owner.isAllOf(EnumCase) then cls.owner
11101124
else NoSymbol
1111-
def parentDerivesFrom(enumCls: Symbol)(using Context) =
1112-
if !firstParent.derivesFrom(enumCls) then
1113-
report.error(i"enum case does not extend its enum $enumCls", enumCase.sourcePos)
1114-
false
1115-
else
1116-
true
1117-
!enumCase.exists || parentDerivesFrom(enumCase.owner.linkedClass)
1118-
}
1125+
if enumCase.exists then
1126+
ensureParentDerivesFrom(enumCase)
1127+
1128+
end checkEnumParent
11191129

11201130
/** Check that all references coming from enum cases in an enum companion object
11211131
* are legal.
@@ -1210,7 +1220,7 @@ trait Checking {
12101220

12111221
trait ReChecking extends Checking {
12121222
import tpd._
1213-
override def checkEnumParent(cls: Symbol, firstParent: Symbol)(using Context): Boolean = true
1223+
override def checkEnumParent(cls: Symbol, firstParent: Symbol)(using Context): Unit = ()
12141224
override def checkEnum(cdef: untpd.TypeDef, cls: Symbol, firstParent: Symbol)(using Context): Unit = ()
12151225
override def checkRefsLegal(tree: tpd.Tree, badOwner: Symbol, allowed: (Name, Symbol) => Boolean, where: String)(using Context): Unit = ()
12161226
override def checkFullyAppliedType(tree: Tree)(using Context): Unit = ()

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2070,20 +2070,17 @@ class Typer extends Namer
20702070
val constr1 = typed(constr).asInstanceOf[DefDef]
20712071
val parentsWithClass = ensureFirstTreeIsClass(parents.mapconserve(typedParent).filterConserve(!_.isEmpty), cdef.nameSpan)
20722072
val parents1 = ensureConstrCall(cls, parentsWithClass)(using superCtx)
2073+
val firstParent = parents1.head.tpe.dealias.typeSymbol
20732074

2074-
lazy val firstParent = parents1.head.tpe.dealias.typeSymbol
2075+
checkEnumParent(cls, firstParent)
20752076

20762077
val self1 = typed(self)(using ctx.outer).asInstanceOf[ValDef] // outer context where class members are not visible
20772078
if (self1.tpt.tpe.isError || classExistsOnSelf(cls.unforcedDecls, self1))
20782079
// fail fast to avoid typing the body with an error type
20792080
cdef.withType(UnspecifiedErrorType)
20802081
else {
20812082
val dummy = localDummy(cls, impl)
2082-
val body1 =
2083-
if checkEnumParent(cls, firstParent) then
2084-
addAccessorDefs(cls, typedStats(impl.body, dummy)(using ctx.inClassContext(self1.symbol))._1)
2085-
else
2086-
Nil
2083+
val body1 = addAccessorDefs(cls, typedStats(impl.body, dummy)(using ctx.inClassContext(self1.symbol))._1)
20872084

20882085
checkNoDoubleDeclaration(cls)
20892086
val impl1 = cpy.Template(impl)(constr1, parents1, Nil, self1, body1)

tests/neg/i6601.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,7 @@ object GADTs2 {
1616
enum Color {
1717
case Red extends AnyRef // error
1818
}
19+
enum Parameterized[T](x: T) {
20+
case Foo extends AnyRef // error
21+
}
1922
}

0 commit comments

Comments
 (0)