diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 3ffef90057ef..366ed459a6a0 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -249,11 +249,11 @@ object Parsers { /** Skip on error to next safe point. */ - protected def skip(): Unit = + protected def skip(stopAtComma: Boolean): Unit = val lastRegion = in.currentRegion def atStop = in.token == EOF - || skipStopTokens.contains(in.token) && (in.currentRegion eq lastRegion) + || ((stopAtComma && in.token == COMMA) || skipStopTokens.contains(in.token)) && (in.currentRegion eq lastRegion) while !atStop do in.nextToken() lastErrorOffset = in.offset @@ -278,7 +278,7 @@ object Parsers { if (in.token == EOF) incompleteInputError(msg) else syntaxError(msg, offset) - skip() + skip(stopAtComma = true) /** Consume one token of the specified type, or * signal an error if it is not there. @@ -346,7 +346,7 @@ object Parsers { false // it's a statement that might be legal in an outer context else in.nextToken() // needed to ensure progress; otherwise we might cycle forever - skip() + skip(stopAtComma=false) true in.observeOutdented() @@ -881,7 +881,8 @@ object Parsers { val next = in.lookahead.token next == LBRACKET || next == LPAREN - /** Is current ident a `*`, and is it followed by a `)` or `, )`? */ + /** Is current ident a `*`, and is it followed by a `)`, `, )`, `,EOF`? The latter two are not + syntactically valid, but we need to include them here for error recovery. */ def followingIsVararg(): Boolean = in.isIdent(nme.raw.STAR) && { val lookahead = in.LookaheadScanner() @@ -890,7 +891,7 @@ object Parsers { || lookahead.token == COMMA && { lookahead.nextToken() - lookahead.token == RPAREN + lookahead.token == RPAREN || lookahead.token == EOF } } diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index 1fee0f52f770..d6ef2646eacf 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -659,8 +659,6 @@ object Scanners { && (token == RPAREN || token == RBRACKET || token == RBRACE || token == OUTDENT) then () /* skip the trailing comma */ - else if token == EOF then // e.g. when the REPL is parsing "val List(x, y, _*," - () /* skip the trailing comma */ else reset() case END => diff --git a/compiler/src/dotty/tools/repl/Main.scala b/compiler/src/dotty/tools/repl/Main.scala index 127ccd10b467..7eb906edc586 100644 --- a/compiler/src/dotty/tools/repl/Main.scala +++ b/compiler/src/dotty/tools/repl/Main.scala @@ -1,6 +1,7 @@ package dotty.tools.repl /** Main entry point to the REPL */ +// To test, run bin/scala object Main { def main(args: Array[String]): Unit = new ReplDriver(args).tryRunning diff --git a/tests/neg/arg-eof.scala b/tests/neg/arg-eof.scala new file mode 100644 index 000000000000..ba860b5dfae0 --- /dev/null +++ b/tests/neg/arg-eof.scala @@ -0,0 +1,3 @@ +object Test: + case class Widget(name: String, other: Int = 5) + Widget(name = "foo", // error // error \ No newline at end of file diff --git a/tests/neg/i1679.scala b/tests/neg/i1679.scala index 08a33bb15596..cadeb85dc8db 100644 --- a/tests/neg/i1679.scala +++ b/tests/neg/i1679.scala @@ -1,5 +1,5 @@ class A[T] object o { // Testing compiler crash, this test should be modified when named type argument are completely implemented - val x: A[T=Int, T=Int] = ??? // error: ']' expected, but '=' found + val x: A[T=Int, T=Int] = ??? // error: ']' expected, but '=' found // error } diff --git a/tests/neg/t1625.check b/tests/neg/t1625.check new file mode 100644 index 000000000000..7e31f49f3729 --- /dev/null +++ b/tests/neg/t1625.check @@ -0,0 +1,8 @@ +-- [E040] Syntax Error: tests/neg/t1625.scala:2:20 --------------------------------------------------------------------- +2 | def foo(x: String*, y: String*, c: String*): Int // error: an identifier expected, but ',' found // error: an identifier expected, but ',' found + | ^ + | an identifier expected, but ',' found +-- [E040] Syntax Error: tests/neg/t1625.scala:2:32 --------------------------------------------------------------------- +2 | def foo(x: String*, y: String*, c: String*): Int // error: an identifier expected, but ',' found // error: an identifier expected, but ',' found + | ^ + | an identifier expected, but ',' found diff --git a/tests/neg/t1625.scala b/tests/neg/t1625.scala index e98ce985238e..41929f0ab476 100644 --- a/tests/neg/t1625.scala +++ b/tests/neg/t1625.scala @@ -1,3 +1,3 @@ trait T3 { - def foo(x: String*, y: String*, c: String*): Int // error: an identifier expected, but ',' found -} \ No newline at end of file + def foo(x: String*, y: String*, c: String*): Int // error: an identifier expected, but ',' found // error: an identifier expected, but ',' found +} diff --git a/tests/neg/t5702-neg-bad-and-wild.check b/tests/neg/t5702-neg-bad-and-wild.check new file mode 100644 index 000000000000..cecfb1dfa996 --- /dev/null +++ b/tests/neg/t5702-neg-bad-and-wild.check @@ -0,0 +1,44 @@ +-- [E032] Syntax Error: tests/neg/t5702-neg-bad-and-wild.scala:10:22 --------------------------------------------------- +10 | case List(1, _*,) => // error: pattern expected // error + | ^ + | pattern expected + | + | longer explanation available when compiling with `-explain` +-- [E032] Syntax Error: tests/neg/t5702-neg-bad-and-wild.scala:12:23 --------------------------------------------------- +12 | case List(1, _*3,) => // error: pattern expected // error // error + | ^ + | pattern expected + | + | longer explanation available when compiling with `-explain` +-- [E032] Syntax Error: tests/neg/t5702-neg-bad-and-wild.scala:15:18 --------------------------------------------------- +15 | case List(x*, 1) => // error: pattern expected + | ^ + | pattern expected + | + | longer explanation available when compiling with `-explain` +-- [E031] Syntax Error: tests/neg/t5702-neg-bad-and-wild.scala:17:18 --------------------------------------------------- +17 | case (1, x: _*) => // error: bad use of _* (sequence pattern not allowed) + | ^ + | * can be used only for last argument + | + | longer explanation available when compiling with `-explain` +-- [E032] Syntax Error: tests/neg/t5702-neg-bad-and-wild.scala:23:17 --------------------------------------------------- +23 | val K(ns @ _*, x) = k // error: pattern expected + | ^ + | pattern expected + | + | longer explanation available when compiling with `-explain` +-- Error: tests/neg/t5702-neg-bad-and-wild.scala:10:21 ----------------------------------------------------------------- +10 | case List(1, _*,) => // error: pattern expected // error + | ^ + | Values of types Null and Int cannot be compared with == or != +-- [E006] Not Found Error: tests/neg/t5702-neg-bad-and-wild.scala:12:20 ------------------------------------------------ +12 | case List(1, _*3,) => // error: pattern expected // error // error + | ^ + | Not found: * + | + | longer explanation available when compiling with `-explain` +-- Error: tests/neg/t5702-neg-bad-and-wild.scala:12:22 ----------------------------------------------------------------- +12 | case List(1, _*3,) => // error: pattern expected // error // error + | ^ + | Values of types Null and Int cannot be compared with == or != diff --git a/tests/neg/t5702-neg-bad-brace.check b/tests/neg/t5702-neg-bad-brace.check new file mode 100644 index 000000000000..92e9fe912a92 --- /dev/null +++ b/tests/neg/t5702-neg-bad-brace.check @@ -0,0 +1,10 @@ +-- [E032] Syntax Error: tests/neg/t5702-neg-bad-brace.scala:8:21 ------------------------------------------------------- +8 | case List(1, _*} => // error: pattern expected + | ^ + | pattern expected + | + | longer explanation available when compiling with `-explain` +-- [E040] Syntax Error: tests/neg/t5702-neg-bad-brace.scala:11:0 ------------------------------------------------------- +11 |} // error: eof expected, but '}' found + |^ + |eof expected, but '}' found diff --git a/tests/neg/t5702-neg-bad-brace.scala b/tests/neg/t5702-neg-bad-brace.scala new file mode 100644 index 000000000000..8a8e10f462aa --- /dev/null +++ b/tests/neg/t5702-neg-bad-brace.scala @@ -0,0 +1,11 @@ + +object Test { + + def main(args: Array[String]) = { + val is = List(1,2,3) + + is match { + case List(1, _*} => // error: pattern expected + } + } +} // error: eof expected, but '}' found diff --git a/tests/neg/trailing-comma-pattern.check b/tests/neg/trailing-comma-pattern.check new file mode 100644 index 000000000000..d0ce15081263 --- /dev/null +++ b/tests/neg/trailing-comma-pattern.check @@ -0,0 +1,6 @@ +-- [E032] Syntax Error: tests/neg/trailing-comma-pattern.scala:3:8 ----------------------------------------------------- +3 |// error + | ^ + | pattern expected + | + | longer explanation available when compiling with `-explain` diff --git a/tests/neg/trailing-comma-pattern.scala b/tests/neg/trailing-comma-pattern.scala new file mode 100644 index 000000000000..02ee158b7ae5 --- /dev/null +++ b/tests/neg/trailing-comma-pattern.scala @@ -0,0 +1,3 @@ +object Test: + val List(x, y, _*, +// error \ No newline at end of file diff --git a/tests/neg/trailing-comma-pattern2.check b/tests/neg/trailing-comma-pattern2.check new file mode 100644 index 000000000000..2759c648ff95 --- /dev/null +++ b/tests/neg/trailing-comma-pattern2.check @@ -0,0 +1,10 @@ +-- [E032] Syntax Error: tests/neg/trailing-comma-pattern2.scala:2:21 --------------------------------------------------- +2 | val List(x, y, _*, ) // error + | ^ + | pattern expected + | + | longer explanation available when compiling with `-explain` +-- [E040] Syntax Error: tests/neg/trailing-comma-pattern2.scala:3:8 ---------------------------------------------------- +3 |// error + | ^ + | '=' expected, but unindent found diff --git a/tests/neg/trailing-comma-pattern2.scala b/tests/neg/trailing-comma-pattern2.scala new file mode 100644 index 000000000000..2ada489ed234 --- /dev/null +++ b/tests/neg/trailing-comma-pattern2.scala @@ -0,0 +1,3 @@ +object Test: + val List(x, y, _*, ) // error +// error \ No newline at end of file diff --git a/tests/pos/trailing-comma-pattern.scala b/tests/pos/trailing-comma-pattern.scala new file mode 100644 index 000000000000..878b3af7748a --- /dev/null +++ b/tests/pos/trailing-comma-pattern.scala @@ -0,0 +1,3 @@ +object Test: + val List(x, y, _*, + ) = List(1, 2, 3) diff --git a/tests/untried/neg/t5702-neg-bad-and-wild.check b/tests/untried/neg/t5702-neg-bad-and-wild.check deleted file mode 100644 index a52136dbf889..000000000000 --- a/tests/untried/neg/t5702-neg-bad-and-wild.check +++ /dev/null @@ -1,28 +0,0 @@ -t5702-neg-bad-and-wild.scala:10: error: bad simple pattern: bad use of _* (a sequence pattern must be the last pattern) - case List(1, _*,) => // bad use of _* (a sequence pattern must be the last pattern) - ^ -t5702-neg-bad-and-wild.scala:10: error: illegal start of simple pattern - case List(1, _*,) => // bad use of _* (a sequence pattern must be the last pattern) - ^ -t5702-neg-bad-and-wild.scala:12: error: illegal start of simple pattern - case List(1, _*3,) => // illegal start of simple pattern - ^ -t5702-neg-bad-and-wild.scala:14: error: bad simple pattern: use _* to match a sequence - case List(1, x*) => // use _* to match a sequence - ^ -t5702-neg-bad-and-wild.scala:15: error: bad simple pattern: trailing * is not a valid pattern - case List(x*, 1) => // trailing * is not a valid pattern - ^ -t5702-neg-bad-and-wild.scala:16: error: bad simple pattern: trailing * is not a valid pattern - case (1, x*) => // trailing * is not a valid pattern - ^ -t5702-neg-bad-and-wild.scala:17: error: bad simple pattern: bad use of _* (sequence pattern not allowed) - case (1, x@_*) => // bad use of _* (sequence pattern not allowed) - ^ -t5702-neg-bad-and-wild.scala:23: error: bad simple pattern: bad use of _* (a sequence pattern must be the last pattern) - val K(ns @ _*, x) = k // bad use of _* (a sequence pattern must be the last pattern) - ^ -t5702-neg-bad-and-wild.scala:24: error: bad simple pattern: bad use of _* (sequence pattern not allowed) - val (b, _ * ) = (5,6) // bad use of _* (sequence pattern not allowed) - ^ -9 errors found diff --git a/tests/untried/neg/t5702-neg-bad-brace.check b/tests/untried/neg/t5702-neg-bad-brace.check deleted file mode 100644 index 503f7d95edc1..000000000000 --- a/tests/untried/neg/t5702-neg-bad-brace.check +++ /dev/null @@ -1,10 +0,0 @@ -t5702-neg-bad-brace.scala:14: error: Unmatched closing brace '}' ignored here - case List(1, _*} => - ^ -t5702-neg-bad-brace.scala:14: error: illegal start of simple pattern - case List(1, _*} => - ^ -t5702-neg-bad-brace.scala:15: error: ')' expected but '}' found. - } - ^ -three errors found diff --git a/tests/untried/neg/t5702-neg-bad-brace.scala b/tests/untried/neg/t5702-neg-bad-brace.scala deleted file mode 100644 index 16a341cf8c17..000000000000 --- a/tests/untried/neg/t5702-neg-bad-brace.scala +++ /dev/null @@ -1,17 +0,0 @@ - -object Test { - - def main(args: Array[String]) { - val is = List(1,2,3) - - is match { -// the erroneous brace is ignored, so we can't halt on it. -// maybe brace healing can detect overlapping unmatched (...} -// In this case, the fix emits an extra error: -// t5702-neg-bad-brace.scala:10: error: Unmatched closing brace '}' ignored here -// t5702-neg-bad-brace.scala:10: error: illegal start of simple pattern (i.e., =>) -// t5702-neg-bad-brace.scala:11: error: ')' expected but '}' found. - case List(1, _*} => - } - } -}