Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check that case classes don't inherit case classes #2790

Merged
merged 3 commits into from Jun 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 14 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
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
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
@@ -0,0 +1,4 @@
case class A()
case class B() extends A() // error
class C extends A()
case class D() extends C // error