diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.scala index 3365459486a4..aa7a58e5024d 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.scala @@ -148,7 +148,8 @@ enum ErrorMessageID extends java.lang.Enum[ErrorMessageID] { IllegalSuperAccessorID, TraitParameterUsedAsParentPrefixID, UnknownNamedEnclosingClassOrObjectID, - IllegalCyclicTypeReferenceID + IllegalCyclicTypeReferenceID, + MissingTypeParameterInTypeAppID 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 f1088b68b27b..ffb1d7299a4a 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1457,6 +1457,15 @@ object messages { val explanation: String = "" } + case class MissingTypeParameterInTypeApp(tpe: Type)(implicit ctx: Context) + extends Message(MissingTypeParameterInTypeAppID) { + val numParams = tpe.typeParams.length + val parameters = if (numParams == 1) "parameter" else "parameters" + val msg: String = em"Missing type $parameters for $tpe" + val kind: String = "Type Mismatch" + val explanation: String = em"A fully applied type is expected but $tpe takes $numParams $parameters." + } + case class DoesNotConformToBound(tpe: Type, which: String, bound: Type)( err: Errors)(implicit ctx: Context) extends Message(DoesNotConformToBoundID) { diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 7df77bcee979..7fc252c5d6b0 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -50,8 +50,7 @@ object Checking { def checkBounds(args: List[tpd.Tree], boundss: List[TypeBounds], instantiate: (Type, List[Type]) => Type, app: Type = NoType)(implicit ctx: Context): Unit = { args.lazyZip(boundss).foreach { (arg, bound) => if (!bound.isLambdaSub && !arg.tpe.hasSimpleKind) - // see MissingTypeParameterFor - ctx.error(ex"missing type parameter(s) for $arg", arg.sourcePos) + errorTree(arg, MissingTypeParameterInTypeApp(arg.tpe)) } for ((arg, which, bound) <- ctx.boundsViolations(args, boundss, instantiate, app)) ctx.error( diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala index eb5c7f4930d6..79718477c6c4 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala @@ -636,6 +636,21 @@ class ErrorMessagesTests extends ErrorMessagesTest { assertEquals("List", tpe.show) } + @Test def missingTypeParameterInTypeApp = + checkMessagesAfter(RefChecks.name) { + """object Scope { + | def f[T] = ??? + | val x = f[List] + | val y = f[Either] + |}""".stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(2, messages) + assertEquals("Missing type parameter for List", messages(1).msg) + assertEquals("Missing type parameters for Either", messages(0).msg) + } + @Test def doesNotConformToBound = checkMessagesAfter(RefChecks.name) { """class WithParam[A <: List[Int]] diff --git a/tests/neg/kinds2.check b/tests/neg/kinds2.check index 7f9f3b20e0bc..cd38fc409479 100644 --- a/tests/neg/kinds2.check +++ b/tests/neg/kinds2.check @@ -1,4 +1,6 @@ --- Error: tests/neg/kinds2.scala:14:4 ---------------------------------------------------------------------------------- +-- [E141] Type Mismatch Error: tests/neg/kinds2.scala:14:4 ------------------------------------------------------------- 14 | f[C] // error: missing type parameter(s) | ^ - | missing type parameter(s) for C + | Missing type parameter for Test.C + +longer explanation available when compiling with `-explain`