diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java index d36e306998df..07a1dd55bc02 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java @@ -105,6 +105,7 @@ public enum ErrorMessageID { ExpectedTypeBoundOrEqualsID, ClassAndCompanionNameClashID, TailrecNotApplicableID, + OnlyStaticObjectsCanExtendPhantomID, ; public int errorNumber() { diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index a172806fe4a9..a815a488cd99 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1826,4 +1826,22 @@ object messages { val explanation = hl"A method annotated ${"@tailrec"} must be declared ${"private"} or ${"final"} so it can't be overridden." } + + case class OnlyStaticObjectsCanExtendPhantom(symbol: Symbol)(implicit ctx: Context) + extends Message(OnlyStaticObjectsCanExtendPhantomID) { + val kind = "Syntax" + val msg = "only static objects can extend scala.Phantom" + val explanation = { + val codeExample = "object MyPhantoms extends Phantom" + + hl""" + |Phantom types are definded by an object extending scala.Phantom. + |This object will represent a universe of phantom types that is completely separated from types in scala.Any or other phantom universes. + |We can define our phantom universe MyPhantoms: + | + |$codeExample + | + """.stripMargin + } + } } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 095ccd29bdfe..81fe76ad48a2 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1427,7 +1427,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit // Check that phantom lattices are defined in a static object if (cls.classParents.exists(_.typeSymbol eq defn.PhantomClass) && !cls.isStaticOwner) - ctx.error("only static objects can extend scala.Phantom", cdef.pos) + ctx.error(OnlyStaticObjectsCanExtendPhantom(cls), cdef.pos) // check value class constraints checkDerivedValueClass(cls, body1) diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala index 0afeb5a21209..e4098bb79717 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala @@ -1051,4 +1051,17 @@ class ErrorMessagesTests extends ErrorMessagesTest { assertEquals("trait G", other.show) } + + @Test def onlyStaticObjectsCanExtendPhantom = + checkMessagesAfter("frontend") { + "class T extends Phantom" + }.expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + + val OnlyStaticObjectsCanExtendPhantom(cls) :: Nil = messages + + assertEquals("class T", cls.show) + } }