From 1f73ba15aa9b33b8d94c09cd72c8965d03f43a88 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 22 Jun 2017 10:45:41 +0200 Subject: [PATCH 1/3] Check that case classes don't inherit case classes --- .../src/dotty/tools/dotc/typer/Checking.scala | 14 +++++++++++- .../src/dotty/tools/dotc/typer/Typer.scala | 22 ++++++++----------- tests/neg/extendsTest.scala | 4 ++++ 3 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 tests/neg/extendsTest.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 33121f7be119..480e29027e3e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -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.""") + 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. @@ -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 = () } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 57e6b89b6f19..7dcb9277e4ca 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -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 = { diff --git a/tests/neg/extendsTest.scala b/tests/neg/extendsTest.scala new file mode 100644 index 000000000000..7c2cf1ac7a85 --- /dev/null +++ b/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 From 0d09c442b869415125d0a01da00348926f1e0cab Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 22 Jun 2017 12:13:31 +0200 Subject: [PATCH 2/3] Fix typos --- compiler/src/dotty/tools/dotc/typer/Checking.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 480e29027e3e..eb401d1c56db 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -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 @@ -653,7 +653,7 @@ trait Checking { /** Check that case classes are not inherited by case classes. */ - def checkCaseInheritance(parent: Symbol, caseCls: ClassSymbol, pos: Position)(implicit ctx: Context): Unit = { + def checkCaseInheritance(parent: Symbol, caseCls: ClassSymbol, pos: Position)(implicit ctx: Context): Unit = parent match { case parent: ClassSymbol => if (parent is Case) From c259d1bad1c133154534ddb796274a1c43911bc4 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 22 Jun 2017 13:07:26 +0200 Subject: [PATCH 3/3] Add position to error message --- compiler/src/dotty/tools/dotc/typer/Checking.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index eb401d1c56db..797a5e6f3e5f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -658,7 +658,7 @@ trait Checking { 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.""") + |To overcome this limitation, use extractors to pattern match on non-leaf nodes.""", pos) else checkCaseInheritance(parent.superClass, caseCls, pos) case _ => }