Skip to content

Commit 94e45f4

Browse files
authored
Merge pull request #2790 from dotty-staging/fix-extend-case
Check that case classes don't inherit case classes
2 parents 9513ed2 + c259d1b commit 94e45f4

File tree

3 files changed

+27
-15
lines changed

3 files changed

+27
-15
lines changed

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ trait Checking {
638638
*
639639
* The standard library relies on this idiom.
640640
*/
641-
def checkTraitInheritance(parent: Symbol, cls: ClassSymbol, pos: Position)(implicit ctx: Context): Unit = {
641+
def checkTraitInheritance(parent: Symbol, cls: ClassSymbol, pos: Position)(implicit ctx: Context): Unit =
642642
parent match {
643643
case parent: ClassSymbol if parent is Trait =>
644644
val psuper = parent.superClass
@@ -650,7 +650,18 @@ trait Checking {
650650
ctx.error(em"illegal trait inheritance: super$csuper does not derive from $parent's super$psuper", pos)
651651
case _ =>
652652
}
653-
}
653+
654+
/** Check that case classes are not inherited by case classes.
655+
*/
656+
def checkCaseInheritance(parent: Symbol, caseCls: ClassSymbol, pos: Position)(implicit ctx: Context): Unit =
657+
parent match {
658+
case parent: ClassSymbol =>
659+
if (parent is Case)
660+
ctx.error(ex"""case $caseCls has case ancestor $parent, but case-to-case inheritance is prohibited.
661+
|To overcome this limitation, use extractors to pattern match on non-leaf nodes.""", pos)
662+
else checkCaseInheritance(parent.superClass, caseCls, pos)
663+
case _ =>
664+
}
654665

655666
/** Check that method parameter types do not reference their own parameter
656667
* or later parameters in the same parameter section.
@@ -686,5 +697,6 @@ trait NoChecking extends Checking {
686697
override def checkNotSingleton(tpt: Tree, where: String)(implicit ctx: Context): Tree = tpt
687698
override def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(implicit ctx: Context) = ()
688699
override def checkTraitInheritance(parentSym: Symbol, cls: ClassSymbol, pos: Position)(implicit ctx: Context) = ()
700+
override def checkCaseInheritance(parentSym: Symbol, caseCls: ClassSymbol, pos: Position)(implicit ctx: Context) = ()
689701
override def checkNoForwardDependencies(vparams: List[ValDef])(implicit ctx: Context): Unit = ()
690702
}

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

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,22 +1343,18 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
13431343
ref
13441344
}
13451345

1346-
def typedParent(tree: untpd.Tree): Tree =
1346+
def typedParent(tree: untpd.Tree): Tree = {
1347+
var result = if (tree.isType) typedType(tree)(superCtx) else typedExpr(tree)(superCtx)
1348+
val psym = result.tpe.typeSymbol
13471349
if (tree.isType) {
1348-
val result = typedType(tree)(superCtx)
1349-
val psym = result.tpe.typeSymbol
1350-
checkTraitInheritance(psym, cls, tree.pos)
13511350
if (psym.is(Trait) && !cls.is(Trait) && !cls.superClass.isSubClass(psym))
1352-
maybeCall(result, psym, psym.primaryConstructor.info)
1353-
else
1354-
result
1355-
}
1356-
else {
1357-
val result = typedExpr(tree)(superCtx)
1358-
checkTraitInheritance(result.symbol, cls, tree.pos)
1359-
checkParentCall(result, cls)
1360-
result
1351+
result = maybeCall(result, psym, psym.primaryConstructor.info)
13611352
}
1353+
else checkParentCall(result, cls)
1354+
checkTraitInheritance(psym, cls, tree.pos)
1355+
if (cls is Case) checkCaseInheritance(psym, cls, tree.pos)
1356+
result
1357+
}
13621358

13631359
/** Checks if one of the decls is a type with the same name as class type member in selfType */
13641360
def classExistsOnSelf(decls: Scope, self: tpd.ValDef): Boolean = {

tests/neg/extendsTest.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
case class A()
2+
case class B() extends A() // error
3+
class C extends A()
4+
case class D() extends C // error

0 commit comments

Comments
 (0)