diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java index a3cde6a9d746..b7ad3692185e 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java @@ -112,6 +112,7 @@ public enum ErrorMessageID { UndefinedNamedTypeParameterID, IllegalStartOfStatementID, TraitIsExpectedID, + TraitRedefinedFinalMethodFromAnyRefID, ; 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 70287cb8d791..be31e609fd2c 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1916,4 +1916,10 @@ object messages { |""" } } + + case class TraitRedefinedFinalMethodFromAnyRef(method: Symbol)(implicit ctx: Context) extends Message(TraitRedefinedFinalMethodFromAnyRefID) { + val kind = "Syntax" + val msg = hl"Traits cannot redefine final $method from ${"class AnyRef"}." + val explanation = "" + } } diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index efecb89d5d68..07164bc68f8d 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -116,7 +116,7 @@ object RefChecks { if (!cls.owner.is(ModuleClass)) { def clashes(sym: Symbol) = sym.isClass && - sym.name.stripModuleClassSuffix == cls.name.stripModuleClassSuffix + sym.name.stripModuleClassSuffix == cls.name.stripModuleClassSuffix val others = cls.owner.linkedClass.info.decls.filter(clashes) others.foreach { other => @@ -606,7 +606,7 @@ object RefChecks { // override a concrete method in Object. The jvm, however, does not. val overridden = decl.matchingDecl(defn.ObjectClass, defn.ObjectType) if (overridden.is(Final)) - ctx.error("trait cannot redefine final method from class AnyRef", decl.pos) + ctx.error(TraitRedefinedFinalMethodFromAnyRef(overridden), decl.pos) } } diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala index e23c5089df88..4282e5aa367d 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala @@ -1172,4 +1172,21 @@ class ErrorMessagesTests extends ErrorMessagesTest { val TraitIsExpected(symbol) :: Nil = messages assertEquals("class B", symbol.show) } + + @Test def traitRedefinedFinalMethodFromAnyRef = + checkMessagesAfter("refchecks") { + """ + |trait C { + | def wait (): Unit + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val TraitRedefinedFinalMethodFromAnyRef(method) = messages.head + assertEquals("method wait", method.show) + } + }