Skip to content

Commit

Permalink
Merge pull request scala#2790 from dotty-staging/fix-extend-case
Browse files Browse the repository at this point in the history
Check that case classes don't inherit case classes
  • Loading branch information
felixmulder authored Jun 23, 2017
2 parents 9513ed2 + c259d1b commit 94e45f4
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 15 deletions.
16 changes: 14 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,7 @@ trait Checking {
*
* The standard library relies on this idiom.
*/
def checkTraitInheritance(parent: Symbol, cls: ClassSymbol, pos: Position)(implicit ctx: Context): Unit = {
def checkTraitInheritance(parent: Symbol, cls: ClassSymbol, pos: Position)(implicit ctx: Context): Unit =
parent match {
case parent: ClassSymbol if parent is Trait =>
val psuper = parent.superClass
Expand All @@ -650,7 +650,18 @@ trait Checking {
ctx.error(em"illegal trait inheritance: super$csuper does not derive from $parent's super$psuper", pos)
case _ =>
}
}

/** Check that case classes are not inherited by case classes.
*/
def checkCaseInheritance(parent: Symbol, caseCls: ClassSymbol, pos: Position)(implicit ctx: Context): Unit =
parent match {
case parent: ClassSymbol =>
if (parent is Case)
ctx.error(ex"""case $caseCls has case ancestor $parent, but case-to-case inheritance is prohibited.
|To overcome this limitation, use extractors to pattern match on non-leaf nodes.""", pos)
else checkCaseInheritance(parent.superClass, caseCls, pos)
case _ =>
}

/** Check that method parameter types do not reference their own parameter
* or later parameters in the same parameter section.
Expand Down Expand Up @@ -686,5 +697,6 @@ trait NoChecking extends Checking {
override def checkNotSingleton(tpt: Tree, where: String)(implicit ctx: Context): Tree = tpt
override def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(implicit ctx: Context) = ()
override def checkTraitInheritance(parentSym: Symbol, cls: ClassSymbol, pos: Position)(implicit ctx: Context) = ()
override def checkCaseInheritance(parentSym: Symbol, caseCls: ClassSymbol, pos: Position)(implicit ctx: Context) = ()
override def checkNoForwardDependencies(vparams: List[ValDef])(implicit ctx: Context): Unit = ()
}
22 changes: 9 additions & 13 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1343,22 +1343,18 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
ref
}

def typedParent(tree: untpd.Tree): Tree =
def typedParent(tree: untpd.Tree): Tree = {
var result = if (tree.isType) typedType(tree)(superCtx) else typedExpr(tree)(superCtx)
val psym = result.tpe.typeSymbol
if (tree.isType) {
val result = typedType(tree)(superCtx)
val psym = result.tpe.typeSymbol
checkTraitInheritance(psym, cls, tree.pos)
if (psym.is(Trait) && !cls.is(Trait) && !cls.superClass.isSubClass(psym))
maybeCall(result, psym, psym.primaryConstructor.info)
else
result
}
else {
val result = typedExpr(tree)(superCtx)
checkTraitInheritance(result.symbol, cls, tree.pos)
checkParentCall(result, cls)
result
result = maybeCall(result, psym, psym.primaryConstructor.info)
}
else checkParentCall(result, cls)
checkTraitInheritance(psym, cls, tree.pos)
if (cls is Case) checkCaseInheritance(psym, cls, tree.pos)
result
}

/** Checks if one of the decls is a type with the same name as class type member in selfType */
def classExistsOnSelf(decls: Scope, self: tpd.ValDef): Boolean = {
Expand Down
4 changes: 4 additions & 0 deletions tests/neg/extendsTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
case class A()
case class B() extends A() // error
class C extends A()
case class D() extends C // error

0 comments on commit 94e45f4

Please sign in to comment.