aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/src/dotty/tools/dotc/parsing/Parsers.scala14
-rw-r--r--compiler/src/dotty/tools/dotc/parsing/Tokens.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala37
-rw-r--r--compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTest.scala2
-rw-r--r--compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala29
6 files changed, 75 insertions, 13 deletions
diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
index 9f4cdbd35..45ae842b6 100644
--- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
+++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
@@ -110,7 +110,8 @@ object Parsers {
*/
def syntaxError(msg: => Message, offset: Int = in.offset): Unit =
if (offset > lastErrorOffset) {
- syntaxError(msg, Position(offset))
+ val length = if (in.name != null) in.name.show.length else 0
+ syntaxError(msg, Position(offset, offset + length))
lastErrorOffset = in.offset
}
@@ -249,11 +250,6 @@ object Parsers {
lastErrorOffset = in.offset
} // DEBUG
- private def expectedMsg(token: Int): String =
- expectedMessage(showToken(token))
- private def expectedMessage(what: String): String =
- s"$what expected but ${showToken(in.token)} found"
-
/** Consume one token of the specified type, or
* signal an error if it is not there.
*
@@ -262,7 +258,7 @@ object Parsers {
def accept(token: Int): Int = {
val offset = in.offset
if (in.token != token) {
- syntaxErrorOrIncomplete(expectedMsg(token))
+ syntaxErrorOrIncomplete(ExpectedTokenButFound(token, in.token, in.name))
}
if (in.token == token) in.nextToken()
offset
@@ -474,7 +470,7 @@ object Parsers {
in.nextToken()
name
} else {
- syntaxErrorOrIncomplete(expectedMsg(IDENTIFIER))
+ syntaxErrorOrIncomplete(ExpectedTokenButFound(IDENTIFIER, in.token, in.name))
nme.ERROR
}
@@ -1055,7 +1051,7 @@ object Parsers {
case Block(Nil, EmptyTree) =>
assert(handlerStart != -1)
syntaxError(
- new EmptyCatchBlock(body),
+ EmptyCatchBlock(body),
Position(handlerStart, endOffset(handler))
)
case _ =>
diff --git a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala
index 280832ef3..8d42e525a 100644
--- a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala
+++ b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala
@@ -17,7 +17,7 @@ abstract class TokensCommon {
def showToken(token: Int) = {
val str = tokenString(token)
- if (keywords contains token) s"'$str'" else str
+ if (isKeyword(token)) s"'$str'" else str
}
val tokenString, debugString = new Array[String](maxToken + 1)
@@ -114,6 +114,8 @@ abstract class TokensCommon {
val keywords: TokenSet
+ def isKeyword(token: Token): Boolean = keywords contains token
+
/** parentheses */
final val LPAREN = 90; enter(LPAREN, "'('")
final val RPAREN = 91; enter(RPAREN, "')'")
diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala
index 2497fb216..ab1222dab 100644
--- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala
+++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala
@@ -119,6 +119,8 @@ class ExtendMessage(_msg: () => Message)(f: String => String) { self =>
class NoExplanation(val msg: String) extends Message(NoExplanation.ID) {
val explanation = ""
val kind = ""
+
+ override def toString(): String = s"NoExplanation($msg)"
}
/** The extractor for `NoExplanation` can be used to check whether any error
diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala
index 4d61f21cf..94611e10d 100644
--- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala
+++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala
@@ -4,10 +4,17 @@ package reporting
package diagnostic
import dotc.core._
-import Contexts.Context, Decorators._, Symbols._, Names._, NameOps._, Types._
+import Contexts.Context
+import Decorators._
+import Symbols._
+import Names._
+import NameOps._
+import Types._
import util.SourcePosition
import config.Settings.Setting
-import interfaces.Diagnostic.{ERROR, WARNING, INFO}
+import interfaces.Diagnostic.{ERROR, INFO, WARNING}
+import dotc.parsing.Scanners.Token
+import dotc.parsing.Tokens
import printing.Highlighting._
import printing.Formatting
@@ -1053,4 +1060,30 @@ object messages {
|""".stripMargin
}
+ case class ExpectedTokenButFound(expected: Token, found: Token, foundName: TermName)(implicit ctx: Context)
+ extends Message(40) {
+ val kind = "Syntax"
+
+ private val expectedText =
+ if (Tokens.isIdentifier(expected)) "an identifier"
+ else Tokens.showToken(expected)
+
+ private val foundText =
+ if (foundName != null) hl"`${foundName.show}`"
+ else Tokens.showToken(found)
+
+ val msg = hl"""${expectedText} expected, but ${foundText} found"""
+
+ private val ifKeyword =
+ if (Tokens.isIdentifier(expected) && Tokens.isKeyword(found))
+ s"""
+ |If you necessarily want to use $foundText as identifier, you may put it in backticks.""".stripMargin
+ else
+ ""
+
+ val explanation =
+ s"""|The text ${foundText} may not occur at that position, the compiler expected ${expectedText}.$ifKeyword
+ |""".stripMargin
+ }
+
}
diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTest.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTest.scala
index 57d66c60b..9be98ee65 100644
--- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTest.scala
+++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTest.scala
@@ -65,7 +65,7 @@ trait ErrorMessagesTest extends DottyTest {
}
def assertMessageCount(expected: Int, messages: List[Message]): Unit =
- assertEquals(
+ assertEquals(messages.mkString,
expected,
messages.length
)
diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala
index d9b7f7f67..697a00510 100644
--- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala
+++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala
@@ -4,6 +4,7 @@ package reporting
import core.Contexts.Context
import diagnostic.messages._
+import dotty.tools.dotc.parsing.Tokens
import org.junit.Assert._
import org.junit.Test
@@ -107,4 +108,32 @@ class ErrorMessagesTests extends ErrorMessagesTest {
assertEquals("value a", definition.show)
}
+ @Test def unexpectedToken =
+ checkMessagesAfter("frontend") {
+ """
+ |object Forward {
+ | def val = "ds"
+ |}
+ """.stripMargin
+ }
+ .expect { (ictx, messages) =>
+ implicit val ctx: Context = ictx
+ val defn = ictx.definitions
+
+ assertMessageCount(1, messages)
+ val ExpectedTokenButFound(expected, found, foundName) :: Nil = messages
+ assertEquals(Tokens.IDENTIFIER, expected)
+ assertEquals(Tokens.VAL, found)
+ assertEquals("val", foundName.show)
+ }
+
+ @Test def expectedToken =
+ checkMessagesAfter("frontend") {
+ """
+ |object Forward {
+ | def `val` = "ds"
+ |}
+ """.stripMargin
+ }
+ .expectNoErrors
}