From e4437f9343a1d5cea4866e0a991db297b3d999d9 Mon Sep 17 00:00:00 2001 From: Miron Aseev Date: Mon, 13 Nov 2017 20:03:57 +0700 Subject: [PATCH 1/3] Add an error message class for a case where a trait is expected --- .../reporting/diagnostic/ErrorMessageID.java | 3 +- .../dotc/reporting/diagnostic/messages.scala | 28 +++++++++++++++++++ .../src/dotty/tools/dotc/typer/Checking.scala | 2 +- .../dotc/reporting/ErrorMessagesTests.scala | 21 ++++++++++++++ 4 files changed, 52 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java index a01e6568df1e..12021e9ba7b7 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java @@ -110,7 +110,8 @@ public enum ErrorMessageID { MissingEmptyArgumentListID, DuplicateNamedTypeParameterID, UndefinedNamedTypeParameterID, - IllegalStartOfStatementID + IllegalStartOfStatementID, + TraitIsExpectedID ; 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 a64061609d40..1dfa5e0597ec 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1888,4 +1888,32 @@ object messages { } val explanation = "A statement is either an import, a definition or an expression." } + + case class TraitIsExpected(tref: TypeRef)(implicit ctx: Context) extends Message(TraitIsExpectedID) { + val kind = "Syntax" + val msg = hl"$tref is not a trait" + val explanation = { + val errorCodeExample = + """class A + |class B + | + |val a = new A with B // will fail with a compile error - B is not a trait""" + val codeExample = + """class A + |trait B + | + |val a = new A with B // compiles normally""" + + hl"""Only traits can be mixed into classes using a ${"with"} keyword. + |Consider the following example: + | + |$errorCodeExample + | + |The example mentioned above would fail because B is not a trait. + |But if you make B a trait it will be compiled without any errors: + | + |$codeExample + |""" + } + } } diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 7e16230fc098..4545c7fd799b 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -548,7 +548,7 @@ trait Checking { def checkClassType(tp: Type, pos: Position, traitReq: Boolean, stablePrefixReq: Boolean)(implicit ctx: Context): Type = tp.underlyingClassRef(refinementOK = false) match { case tref: TypeRef => - if (traitReq && !(tref.symbol is Trait)) ctx.error(ex"$tref is not a trait", pos) + if (traitReq && !(tref.symbol is Trait)) ctx.error(TraitIsExpected(tref), pos) if (stablePrefixReq && ctx.phase <= ctx.refchecksPhase) checkStable(tref.prefix, pos) tp case _ => diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala index 8238173aea65..19cae48dd16e 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala @@ -1151,4 +1151,25 @@ class ErrorMessagesTests extends ErrorMessagesTest { assertEquals(IllegalStartOfStatement(isModifier = false), err) assertEquals(IllegalStartOfStatement(isModifier = true), errWithModifier) } + + @Test def traitIsExpected = + checkMessagesAfter("frontend") { + """ + |class A + |class B + | + |object Test { + | def main(args: Array[String]): Unit = { + | val a = new A with B + | } + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val TraitIsExpected(tref) :: Nil = messages + assertEquals("B", tref.show) + } } From 546bc4c7f87b88bda6176019480b8b432c7f01cc Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 13 Nov 2017 19:13:27 +0100 Subject: [PATCH 2/3] Add missing comma --- .../dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java index 12021e9ba7b7..a3cde6a9d746 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java @@ -111,7 +111,7 @@ public enum ErrorMessageID { DuplicateNamedTypeParameterID, UndefinedNamedTypeParameterID, IllegalStartOfStatementID, - TraitIsExpectedID + TraitIsExpectedID, ; public int errorNumber() { From 20361265ecbc3422c46254e31fd8c7b55c00863f Mon Sep 17 00:00:00 2001 From: Miron Aseev Date: Tue, 14 Nov 2017 01:35:37 +0700 Subject: [PATCH 3/3] Address PR tasks --- .../dotty/tools/dotc/reporting/diagnostic/messages.scala | 8 ++++---- compiler/src/dotty/tools/dotc/typer/Checking.scala | 2 +- .../dotty/tools/dotc/reporting/ErrorMessagesTests.scala | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 1dfa5e0597ec..70287cb8d791 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1889,20 +1889,20 @@ object messages { val explanation = "A statement is either an import, a definition or an expression." } - case class TraitIsExpected(tref: TypeRef)(implicit ctx: Context) extends Message(TraitIsExpectedID) { + case class TraitIsExpected(symbol: Symbol)(implicit ctx: Context) extends Message(TraitIsExpectedID) { val kind = "Syntax" - val msg = hl"$tref is not a trait" + val msg = hl"$symbol is not a trait" val explanation = { val errorCodeExample = """class A |class B | - |val a = new A with B // will fail with a compile error - B is not a trait""" + |val a = new A with B // will fail with a compile error - class B is not a trait""".stripMargin val codeExample = """class A |trait B | - |val a = new A with B // compiles normally""" + |val a = new A with B // compiles normally""".stripMargin hl"""Only traits can be mixed into classes using a ${"with"} keyword. |Consider the following example: diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 4545c7fd799b..799932f97bc8 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -548,7 +548,7 @@ trait Checking { def checkClassType(tp: Type, pos: Position, traitReq: Boolean, stablePrefixReq: Boolean)(implicit ctx: Context): Type = tp.underlyingClassRef(refinementOK = false) match { case tref: TypeRef => - if (traitReq && !(tref.symbol is Trait)) ctx.error(TraitIsExpected(tref), pos) + if (traitReq && !(tref.symbol is Trait)) ctx.error(TraitIsExpected(tref.symbol), pos) if (stablePrefixReq && ctx.phase <= ctx.refchecksPhase) checkStable(tref.prefix, pos) tp case _ => diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala index 19cae48dd16e..e23c5089df88 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala @@ -1169,7 +1169,7 @@ class ErrorMessagesTests extends ErrorMessagesTest { implicit val ctx: Context = ictx assertMessageCount(1, messages) - val TraitIsExpected(tref) :: Nil = messages - assertEquals("B", tref.show) + val TraitIsExpected(symbol) :: Nil = messages + assertEquals("class B", symbol.show) } }