diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.scala index a9dcebd702f7..84cf4d8d0578 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.scala @@ -147,7 +147,8 @@ enum ErrorMessageID extends java.lang.Enum[ErrorMessageID] { StaticFieldsShouldPrecedeNonStaticID, IllegalSuperAccessorID, TraitParameterUsedAsParentPrefixID, - UnknownNamedEnclosingClassOrObjectID + UnknownNamedEnclosingClassOrObjectID, + ImplicitDefinitionNeedsExplicitTypeID 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 608cd0c1584a..9d3fbba0980c 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -2392,4 +2392,12 @@ object messages { |current scope. """.stripMargin } + + case class ImplicitDefinitionNeedsExplicitType(sym: Symbol, kindOfType: Option[String])(implicit val ctx: Context) + extends Message(ImplicitDefinitionNeedsExplicitTypeID) { + val kind: String = "Type" + val msg: String = + em"implicit definition of ${sym.show} needs explicit ${kindOfType.map(_ + " ").getOrElse("")}type" + val explanation: String = "" + } } diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 76e51e87ae8b..98cea3916509 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -762,8 +762,8 @@ class Namer { typer: Typer => else bound } - def missingType(sym: Symbol, modifier: String)(implicit ctx: Context): Unit = { - ctx.error(s"${modifier}type of implicit definition needs to be given explicitly", sym.sourcePos) + def missingType(sym: Symbol, kindOfType: Option[String])(implicit ctx: Context): Unit = { + ctx.error(ImplicitDefinitionNeedsExplicitType(sym, kindOfType), sym.sourcePos) sym.resetFlag(GivenOrImplicit) } @@ -1131,7 +1131,7 @@ class Namer { typer: Typer => if (ptype.typeParams.isEmpty) ptype else { if (denot.is(ModuleClass) && denot.sourceModule.isOneOf(GivenOrImplicit)) - missingType(denot.symbol, "parent ")(creationContext) + missingType(denot.symbol, Some("parent"))(creationContext) fullyDefinedType(typedAheadExpr(parent).tpe, "class parent", parent.span) } case _ => @@ -1381,8 +1381,8 @@ class Namer { typer: Typer => else { if (sym.is(Implicit)) mdef match { - case _: DefDef => missingType(sym, "result ") - case _: ValDef if sym.owner.isType => missingType(sym, "") + case _: DefDef => missingType(sym, Some("result")) + case _: ValDef if sym.owner.isType => missingType(sym, None) case _ => } lhsType orElse WildcardType diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala index b56a103468a1..03d00976e469 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala @@ -1672,4 +1672,36 @@ class ErrorMessagesTests extends ErrorMessagesTest { val UnknownNamedEnclosingClassOrObject(name) :: Nil = messages assertEquals("doesNotExist", name.show) } + + @Test def implicitDefinitionNeedsExplicitTypeValue() = + checkMessagesAfter(RefChecks.name) { + """ + |class TestObject { + | implicit val foo = 5 + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val ImplicitDefinitionNeedsExplicitType(sym, kindOfType) :: Nil = messages + assertEquals("value foo", sym.show) + assertEquals(None, kindOfType) + } + + @Test def implicitDefinitionNeedsExplicitTypeDef() = + checkMessagesAfter(RefChecks.name) { + """ + |class TestObject { + | implicit def bar = 6 + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val ImplicitDefinitionNeedsExplicitType(sym, kindOfType) :: Nil = messages + assertEquals("method bar", sym.show) + assertEquals(Some("result"), kindOfType) + } }