diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java index c7b724b70cad..5b1fe75b5366 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java @@ -88,6 +88,7 @@ public enum ErrorMessageID { ValueClassNeedsExactlyOneValParamID, OnlyCaseClassOrCaseObjectAllowedID, ExpectedClassOrObjectDefID, + AnonymousFunctionMissingParamTypeID ; 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 621ab3efcf96..bbad10bcef1e 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -176,6 +176,34 @@ object messages { |Or, add an explicit `()' as a parameter list to ${cdef.name}.""" } + case class AnonymousFunctionMissingParamType(param: untpd.ValDef, + args: List[untpd.Tree], + tree: untpd.Function, + pt: Type) + (implicit ctx: Context) + extends Message(AnonymousFunctionMissingParamTypeID) { + val kind = "Syntax" + + val msg = { + val ofFun = + if (MethodType.syntheticParamNames(args.length + 1) contains param.name) + i" of expanded function $tree" + else + "" + + i"missing parameter type for parameter ${param.name}$ofFun, expected = $pt" + } + + val explanation = + hl"""|Anonymous functions must define a type. For example, if you define a function like this one: + | + |${"val f = { case xs @ List(1, 2, 3) => Some(xs) }"} + | + |Make sure you give it a type of what you expect to match and help the type inference system: + | + |${"val f: Seq[Int] => Option[List[Int]] = { case xs @ List(1, 2, 3) => Some(xs) }"} """ + } + // Type Errors ------------------------------------------------------------ // case class DuplicateBind(bind: untpd.Bind, tree: untpd.CaseDef)(implicit ctx: Context) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 0c08fcf14770..237602f56ae1 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -762,12 +762,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } case _ => } - val ofFun = - if (MethodType.syntheticParamNames(args.length + 1) contains param.name) - i" of expanded function $tree" - else - "" - errorType(i"missing parameter type for parameter ${param.name}$ofFun, expected = $pt", param.pos) + errorType(AnonymousFunctionMissingParamType(param, args, tree, pt), param.pos) } def protoFormal(i: Int): Type = diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala index 1e5f73fe2cbd..d1750be777ab 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala @@ -802,5 +802,22 @@ class ErrorMessagesTests extends ErrorMessagesTest { val err :: Nil = messages assertEquals(err, ExpectedClassOrObjectDef()) } + @Test def anonymousFunctionMissingParamType = + checkMessagesAfter("refchecks") { + """ + |object AnonymousF { + | val f = { case l@List(1,2,3) => Some(l) } + |}""".stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + val defn = ictx.definitions + + assertMessageCount(1, messages) + val AnonymousFunctionMissingParamType(param, args, _, pt) :: Nil = messages + assertEquals("x$1", param.show) + assertEquals(s"List(ValDef(${param.show},TypeTree,EmptyTree))", args.toString) + assertEquals("?", pt.show) + } }