Skip to content

Commit d152232

Browse files
committed
WIP: Disallow extending both Any and PhantomAny
1 parent 8ade045 commit d152232

File tree

2 files changed

+35
-15
lines changed

2 files changed

+35
-15
lines changed

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,6 +1173,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
11731173
ctx.featureWarning(nme.dynamics.toString, "extension of type scala.Dynamic", isScala2Feature = true,
11741174
cls, isRequired, cdef.pos)
11751175
}
1176+
checkPhantomInheritance(cdef1, parents1)
11761177
cdef1
11771178

11781179
// todo later: check that
@@ -1218,13 +1219,36 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
12181219

12191220
/** Ensure that first parent tree refers to a real class. */
12201221
def ensureFirstIsClass(parents: List[Tree], pos: Position)(implicit ctx: Context): List[Tree] = parents match {
1222+
case p :: ps if p.tpe.classSymbol.derivesFrom(defn.PhantomAnyClass) => parents // TODO add PhantomAny as first parent
12211223
case p :: ps if p.tpe.classSymbol.isRealClass => parents
12221224
case _ =>
12231225
// add synthetic class type
12241226
val first :: _ = ensureFirstIsClass(parents.tpes)
12251227
TypeTree(checkFeasible(first, pos, d"\n in inferred parent $first")).withPos(pos) :: parents
12261228
}
12271229

1230+
/** Check that a class definition does not inherit from Any and PhantomAny at the same time */
1231+
private def checkPhantomInheritance(cdef: untpd.TypeDef, parents: List[Tree])(implicit ctx: Context): Unit = {
1232+
/** Returns true iff it extends Any and PhantomAny at the same time.
1233+
* It assumes that the parents do not have conflicts
1234+
*/
1235+
@tailrec def hasPhantomParentsConflicts(ls: List[Tree], seenNonPhantom: Boolean, seenPhantom: Boolean): Boolean = ls match {
1236+
case _ if seenNonPhantom && seenPhantom => true
1237+
case x :: xs =>
1238+
if (x.tpe.derivesFrom(defn.PhantomAnyClass)) hasPhantomParentsConflicts(xs, seenNonPhantom, true)
1239+
else hasPhantomParentsConflicts(xs, true, seenPhantom)
1240+
case Nil => false
1241+
}
1242+
1243+
if (hasPhantomParentsConflicts(parents, false, false)) {
1244+
val perfix =
1245+
if (cdef.symbol.flags.is(Flags.Trait)) "A trait"
1246+
else if (cdef.symbol.flags.is(Flags.Abstract)) "An abstract class"
1247+
else "A class"
1248+
ctx.error(perfix + " cannot extend both Any and PhantomAny.", cdef.pos)
1249+
}
1250+
}
1251+
12281252
/** If this is a real class, make sure its first parent is a
12291253
* constructor call. Cannot simply use a type. Overridden in ReTyper.
12301254
*/

tests/neg/phantomClass.scala

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,16 @@ import dotty.phantom.PhantomNothing
44
trait Foo
55
trait Boo extends PhantomAny
66

7-
trait TraitBlinky extends PhantomAny with Foo // FIXME
8-
trait TraitPinky extends Foo with Boo // FIXME
9-
trait TraitInky extends Boo with Foo // FIXME
7+
trait TraitBlinky extends PhantomAny with Foo // error
8+
trait TraitPinky extends Foo with Boo // error
9+
trait TraitInky extends Boo with Foo // error
1010

11-
abstract class AbstractClassBlinky extends AnyRef with PhantomAny // error
12-
abstract class AbstractClassPinky extends PhantomAny with AnyRef // error
13-
abstract class AbstractClassInky extends AnyRef with Boo // FIXME
14-
abstract class AbstractClassClyde extends PhantomAny with Foo // FIXME
15-
abstract class AbstractClassBlinky2 extends Foo with Boo // FIXME
16-
abstract class AbstractClassPiniky2 extends Boo with Foo // FIXME
11+
abstract class AbstractClassInky extends AnyRef with Boo // error
12+
abstract class AbstractClassClyde extends PhantomAny with Foo // error
13+
abstract class AbstractClassBlinky2 extends Foo with Boo // error
14+
abstract class AbstractClassPiniky2 extends Boo with Foo // error
1715

18-
class ClassBlinky extends AnyRef with PhantomAny // error
19-
class ClassPinky extends PhantomAny with AnyRef // error
20-
class ClassInky extends AnyRef with Boo // FIXME
21-
class ClassClyde extends PhantomAny with Foo // FIXME
22-
class ClassBlinky2 extends Foo with Boo // FIXME
23-
class ClassPiniky2 extends Boo with Foo // FIXME
16+
class ClassInky extends AnyRef with Boo // error
17+
class ClassClyde extends PhantomAny with Foo // error
18+
class ClassBlinky2 extends Foo with Boo // error
19+
class ClassPiniky2 extends Boo with Foo // error

0 commit comments

Comments
 (0)