diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java index 37c6aee6540b..b4dbd031bea9 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java @@ -96,6 +96,7 @@ public enum ErrorMessageID { WrongNumberOfParametersID, DuplicatePrivateProtectedQualifierID, ExpectedStartOfTopLevelDefinitionID, + MissingReturnTypeWithReturnStatementID, ; 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 848832dd8c0c..6bd4069fc2a9 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -598,6 +598,17 @@ object messages { |}""" } + case class MissingReturnTypeWithReturnStatement(method: Symbol)(implicit ctx: Context) + extends Message(MissingReturnTypeWithReturnStatementID) { + val kind = "Syntax" + val msg = hl"$method has a return statement; it needs a result type" + val explanation = + hl"""|If a method contains a ${"return"} statement, it must have an + |explicit return type. For example: + | + |${"def good: Int /* explicit return type */ = return 1"}""" + } + case class YieldOrDoExpectedInForComprehension()(implicit ctx: Context) extends Message(YieldOrDoExpectedInForComprehensionID) { val kind = "Syntax" diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index bd5ff738ff2d..a9055e331ac0 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -987,7 +987,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit if (owner.isInlineMethod) (EmptyTree, errorType(em"no explicit return allowed from inline $owner", tree.pos)) else if (!owner.isCompleted) - (EmptyTree, errorType(em"$owner has return statement; needs result type", tree.pos)) + (EmptyTree, errorType(MissingReturnTypeWithReturnStatement(owner), tree.pos)) else { val from = Ident(TermRef(NoPrefix, owner.asTerm)) val proto = returnProto(owner, cx.scope) diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala index 7749f80ecaf0..aa473912ed7d 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala @@ -955,4 +955,19 @@ class ErrorMessagesTests extends ErrorMessagesTest { assertEquals(ExpectedStartOfTopLevelDefinition(), err) } + + @Test def missingReturnTypeWithReturnStatement = + checkMessagesAfter("frontend") { + """class BadFunction { + | def bad() = { return "fail" } + |} + """.stripMargin + }.expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + + val MissingReturnTypeWithReturnStatement(method) :: Nil = messages + assertEquals(method.name.show, "bad") + } }