diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java index e98659c1663c..37a368b00823 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java @@ -100,6 +100,7 @@ public enum ErrorMessageID { NoReturnFromInlineID, ReturnOutsideMethodDefinitionID, UncheckedTypePatternID, + ExtendFinalClassID, ; 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 6da65f77d534..474b07e0415a 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1770,4 +1770,12 @@ object messages { |""" } + case class ExtendFinalClass(clazz:Symbol, finalClazz: Symbol)(implicit ctx: Context) + extends Message(ExtendFinalClassID) { + val kind = "Syntax" + val msg = hl"$clazz cannot extend ${"final"} $finalClazz" + val explanation = + hl"""A class marked with the ${"final"} keyword cannot be extended""" + } + } diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index abbf36bf50f7..62bd705acc6e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -876,7 +876,7 @@ class Namer { typer: Typer => else { val pclazz = pt.typeSymbol if (pclazz.is(Final)) - ctx.error(em"cannot extend final $pclazz", cls.pos) + ctx.error(ExtendFinalClass(cls, pclazz), cls.pos) if (pclazz.is(Sealed) && pclazz.associatedFile != cls.associatedFile) ctx.error(em"cannot extend sealed $pclazz in different compilation unit", cls.pos) pt diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala index a5a2fff1ba5f..2961a5c8c42f 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala @@ -998,4 +998,16 @@ class ErrorMessagesTests extends ErrorMessagesTest { val ReturnOutsideMethodDefinition(owner) :: Nil = messages assertEquals("object A", owner.show) } + @Test def extendFinalClass = checkMessagesAfter("refchecks") { + """final class A + | + |class B extends A + """.stripMargin + }.expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val ExtendFinalClass(extender, parent) :: Nil = messages + assertEquals(extender.show, "class B") + assertEquals(parent.show, "class A") + } }