diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 85c3e21f1358..e9e20394a86d 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1431,9 +1431,9 @@ object Parsers { case FORSOME => syntaxError(ExistentialTypesNoLongerSupported()); t case _ => if (imods.isOneOf(GivenOrImplicit) && !t.isInstanceOf[FunctionWithMods]) - syntaxError("Types with implicit keyword can only be function types `implicit (...) => ...`", implicitKwPos(start)) + syntaxError(ImplicitTypesCanOnlyBeFunctionTypes(), implicitKwPos(start)) if (imods.is(Erased) && !t.isInstanceOf[FunctionWithMods]) - syntaxError("Types with erased keyword can only be function types `erased (...) => ...`", implicitKwPos(start)) + syntaxError(ErasedTypesCanOnlyBeFunctionTypes(), implicitKwPos(start)) t } } diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.scala index aa7a58e5024d..e2aecdfbb018 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.scala @@ -149,7 +149,9 @@ enum ErrorMessageID extends java.lang.Enum[ErrorMessageID] { TraitParameterUsedAsParentPrefixID, UnknownNamedEnclosingClassOrObjectID, IllegalCyclicTypeReferenceID, - MissingTypeParameterInTypeAppID + MissingTypeParameterInTypeAppID, + ImplicitTypesCanOnlyBeFunctionTypesID, + ErasedTypesCanOnlyBeFunctionTypesID def errorNumber = ordinal - 2 } diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index ffb1d7299a4a..739a8f92a3b5 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -2381,4 +2381,18 @@ object messages { val msg: String = i"illegal cyclic type reference: ${where} ${hl(lastChecked.show)} of $sym refers back to the type itself" val explanation: String = "" } + + case class ImplicitTypesCanOnlyBeFunctionTypes()(implicit val ctx: Context) + extends Message(ImplicitTypesCanOnlyBeFunctionTypesID) { + val kind: String = "Syntax" + val msg: String = "Types with given keyword can only be function types `given (...) => ...`" + val explanation: String = "" + } + + case class ErasedTypesCanOnlyBeFunctionTypes()(implicit val ctx: Context) + extends Message(ErasedTypesCanOnlyBeFunctionTypesID) { + val kind: String = "Syntax" + val msg: String = "Types with erased keyword can only be function types `erased (...) => ...`" + val explanation: String = "" + } } diff --git a/compiler/test/dotty/tools/DottyTest.scala b/compiler/test/dotty/tools/DottyTest.scala index 0300a12f6e0a..17d594240d32 100644 --- a/compiler/test/dotty/tools/DottyTest.scala +++ b/compiler/test/dotty/tools/DottyTest.scala @@ -42,6 +42,7 @@ trait DottyTest extends ContextEscapeDetection { protected def initializeCtx(fc: FreshContext): Unit = { fc.setSetting(fc.settings.encoding, "UTF8") fc.setSetting(fc.settings.classpath, TestConfiguration.basicClasspath) + fc.setSetting(fc.settings.YerasedTerms, true) fc.setProperty(ContextDoc, new ContextDocstrings) } diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala index 79718477c6c4..d89a5479d0d2 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala @@ -1684,4 +1684,30 @@ class ErrorMessagesTests extends ErrorMessagesTest { assertEquals("alias", where) assertEquals("List[X]", lastChecked.show) } + + @Test def implicitTypesCanOnlyBeFunctionTypesSuccess() = + checkMessagesAfter(RefChecks.name) ("def foo(f: (given Int) => Int): Int = 1") + .expectNoErrors + + @Test def erasedTypesCanOnlyBeFunctionTypesSuccess() = + checkMessagesAfter(FrontEnd.name) ("def foo(f: (erased Int) => Int): Int = 1") + .expectNoErrors + + @Test def implicitTypesCanOnlyBeFunctionTypesFailed() = + checkMessagesAfter(FrontEnd.name) ("def foo(f: (given Int)): Int = 1") + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val ImplicitTypesCanOnlyBeFunctionTypes() :: Nil = messages + assertEquals("Types with given keyword can only be function types `given (...) => ...`", messages.head.msg) + } + + @Test def erasedTypesCanOnlyBeFunctionTypesFailed() = + checkMessagesAfter(FrontEnd.name) ("def foo(f: (erased Int)): Int = 1") + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val ErasedTypesCanOnlyBeFunctionTypes() :: Nil = messages + assertEquals("Types with erased keyword can only be function types `erased (...) => ...`", messages.head.msg) + } }