diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 541b50bf4079..7e89710e4a39 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -105,6 +105,13 @@ object Parsers { def sourcePos(off: Int = in.offset): SourcePosition = source atPos Position(off) + /** in.offset, except if this is at a new line, in which case `lastOffset` is preferred. */ + def expectedOffset: Int = { + val current = sourcePos(in.offset) + val last = sourcePos(in.lastOffset) + if (current.line != last.line) in.lastOffset else in.offset + } + /* ------------- ERROR HANDLING ------------------------------------------- */ /** The offset where the last syntax error was reported, or if a skip to a * safepoint occurred afterwards, the offset of the safe point. @@ -116,7 +123,7 @@ object Parsers { */ def syntaxError(msg: => Message, offset: Int = in.offset): Unit = if (offset > lastErrorOffset) { - val length = if (in.name != null) in.name.show.length else 0 + val length = if (offset == in.offset && in.name != null) in.name.show.length else 0 syntaxError(msg, Position(offset, offset + length)) lastErrorOffset = in.offset } @@ -275,13 +282,13 @@ object Parsers { /** If at end of file, issue an incompleteInputError. * Otherwise issue a syntax error and skip to next safe point. */ - def syntaxErrorOrIncomplete(msg: => Message): Unit = + def syntaxErrorOrIncomplete(msg: => Message, offset: Int = in.offset): Unit = if (in.token == EOF) incompleteInputError(msg) else { - syntaxError(msg) + syntaxError(msg, offset) skip() lastErrorOffset = in.offset - } // DEBUG + } /** Consume one token of the specified type, or * signal an error if it is not there. @@ -1456,7 +1463,7 @@ object Parsers { case _ => if (isLiteral) literal() else { - syntaxErrorOrIncomplete(IllegalStartSimpleExpr(tokenString(in.token))) + syntaxErrorOrIncomplete(IllegalStartSimpleExpr(tokenString(in.token)), expectedOffset) errorTermTree } } @@ -1748,7 +1755,7 @@ object Parsers { case _ => if (isLiteral) literal(inPattern = true) else { - syntaxErrorOrIncomplete(IllegalStartOfSimplePattern()) + syntaxErrorOrIncomplete(IllegalStartOfSimplePattern(), expectedOffset) errorTermTree } } diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index d18d2c9a15ea..ef3352126100 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -569,19 +569,9 @@ object messages { case class IllegalStartSimpleExpr(illegalToken: String)(implicit ctx: Context) extends Message(IllegalStartSimpleExprID) { val kind: String = "Syntax" - val msg: String = "Illegal start of simple expression" + val msg: String = "expression expected" val explanation: String = { - hl"""|An expression yields a value. In the case of the simple expression, this error - |commonly occurs when there's a missing parenthesis or brace. The reason being - |that a simple expression is one of the following: - | - |- Block - |- Expression in parenthesis - |- Identifier - |- Object creation - |- Literal - | - |which cannot start with ${Red(illegalToken)}.""" + hl"""|An expression cannot start with ${Red(illegalToken)}.""" } } @@ -932,7 +922,7 @@ object messages { case class IllegalStartOfSimplePattern()(implicit ctx: Context) extends Message(IllegalStartOfSimplePatternID) { val kind: String = "Syntax" - val msg: String = "Illegal start of simple pattern" + val msg: String = "pattern expected" val explanation: String = { val sipCode = """def f(x: Int, y: Int) = x match { diff --git a/language-server/test/dotty/tools/languageserver/DiagnosticsTest.scala b/language-server/test/dotty/tools/languageserver/DiagnosticsTest.scala index 35bbae7987c7..4f9b8f47a232 100644 --- a/language-server/test/dotty/tools/languageserver/DiagnosticsTest.scala +++ b/language-server/test/dotty/tools/languageserver/DiagnosticsTest.scala @@ -21,7 +21,7 @@ class DiagnosticsTest { | Nil.map(x => x).filter(x$m1 =>$m2) |$m3}""".withSource .diagnostics(m1, - (m2 to m3, "Illegal start of simple expression", Error, Some(IllegalStartSimpleExprID)), + (m2 to m3, "expression expected", Error, Some(IllegalStartSimpleExprID)), (m1 to m1, """Found: Null |Required: Boolean""".stripMargin, Error, Some(TypeMismatchID)) ) diff --git a/tests/neg/errpos.scala b/tests/neg/errpos.scala new file mode 100644 index 000000000000..7e7092fc7f2c --- /dev/null +++ b/tests/neg/errpos.scala @@ -0,0 +1,16 @@ +object Test { + val x = // error: expression expected + val y = 2 // error: ';' expected + + val z = // error: expression expected + + // ... + val a = 3 // error: ';' expected + + val b = type // error: expression expected (on "type") + + 1 match { + case // error: pattern expected + case 2 => "" + } +} \ No newline at end of file