Skip to content

Commit b077100

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 d692104 commit b077100

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
@@ -1102,21 +1102,31 @@ trait Checking {
11021102
report.error(ClassCannotExtendEnum(cls, firstParent), cdef.sourcePos)
11031103
}
11041104

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

11211131
/** Check that all references coming from enum cases in an enum companion object
11221132
* are legal.
@@ -1211,7 +1221,7 @@ trait Checking {
12111221

12121222
trait ReChecking extends Checking {
12131223
import tpd._
1214-
override def checkEnumParent(cls: Symbol, firstParent: Symbol)(using Context): Boolean = true
1224+
override def checkEnumParent(cls: Symbol, firstParent: Symbol)(using Context): Unit = ()
12151225
override def checkEnum(cdef: untpd.TypeDef, cls: Symbol, firstParent: Symbol)(using Context): Unit = ()
12161226
override def checkRefsLegal(tree: tpd.Tree, badOwner: Symbol, allowed: (Name, Symbol) => Boolean, where: String)(using Context): Unit = ()
12171227
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)