diff --git a/community-build/community-projects/protoquill b/community-build/community-projects/protoquill index 12b3649dfe93..16d26fcb3072 160000 --- a/community-build/community-projects/protoquill +++ b/community-build/community-projects/protoquill @@ -1 +1 @@ -Subproject commit 12b3649dfe93229d1e19fd698db4ee1b8a1ffddd +Subproject commit 16d26fcb30720b9aa81d29f08b9da10916e269a2 diff --git a/community-build/community-projects/scalatest b/community-build/community-projects/scalatest index 89a3f6fb503a..9b2479aeb85f 160000 --- a/community-build/community-projects/scalatest +++ b/community-build/community-projects/scalatest @@ -1 +1 @@ -Subproject commit 89a3f6fb503a034439fe7943d6462458875d8d40 +Subproject commit 9b2479aeb85fe2828c67da9edc6c4688d633a5d3 diff --git a/community-build/community-projects/specs2 b/community-build/community-projects/specs2 index 0652daeefb57..e1ae96e7a55f 160000 --- a/community-build/community-projects/specs2 +++ b/community-build/community-projects/specs2 @@ -1 +1 @@ -Subproject commit 0652daeefb57c2d51e3f16ea5c44929bdba722bf +Subproject commit e1ae96e7a55fed2268f9ccd391687a5ac96ee4df diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 893f797709e1..2e0aaedb3788 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -225,7 +225,7 @@ object Parsers { || allowedMods.contains(in.token) || in.isSoftModifierInModifierPosition && !excludedSoftModifiers.contains(in.name) - def isStatSep: Boolean = in.isNewLine || in.token == SEMI + def isStatSep: Boolean = in.isStatSep /** A '$' identifier is treated as a splice if followed by a `{`. * A longer identifier starting with `$` is treated as a splice/id combination @@ -252,13 +252,8 @@ object Parsers { /** Skip on error to next safe point. */ - protected def skip(stopAtComma: Boolean): Unit = - val lastRegion = in.currentRegion - def atStop = - in.token == EOF - || ((stopAtComma && in.token == COMMA) || skipStopTokens.contains(in.token)) && (in.currentRegion eq lastRegion) - while !atStop do - in.nextToken() + def skip(): Unit = + in.skip() lastErrorOffset = in.offset def warning(msg: Message, sourcePos: SourcePosition): Unit = @@ -272,35 +267,37 @@ object Parsers { /** Issue an error at current offset that input is incomplete */ def incompleteInputError(msg: Message): Unit = - report.incompleteInputError(msg, source.atSpan(Span(in.offset))) + if in.offset != lastErrorOffset then + report.incompleteInputError(msg, source.atSpan(Span(in.offset))) /** If at end of file, issue an incompleteInputError. * Otherwise issue a syntax error and skip to next safe point. */ def syntaxErrorOrIncomplete(msg: Message, offset: Int = in.offset): Unit = - if (in.token == EOF) incompleteInputError(msg) + if in.token == EOF then + incompleteInputError(msg) else syntaxError(msg, offset) - skip(stopAtComma = true) + skip() def syntaxErrorOrIncomplete(msg: Message, span: Span): Unit = - if (in.token == EOF) incompleteInputError(msg) + if in.token == EOF then + incompleteInputError(msg) else syntaxError(msg, span) - skip(stopAtComma = true) + skip() /** Consume one token of the specified type, or * signal an error if it is not there. * * @return The offset at the start of the token to accept */ - def accept(token: Int): Int = { + def accept(token: Int): Int = val offset = in.offset - if (in.token != token) + if in.token != token then syntaxErrorOrIncomplete(ExpectedTokenButFound(token, in.token)) - if (in.token == token) in.nextToken() + if in.token == token then in.nextToken() offset - } def accept(name: Name): Int = { val offset = in.offset @@ -355,7 +352,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(stopAtComma=false) + skip() true in.observeOutdented() @@ -562,18 +559,14 @@ object Parsers { def inDefScopeBraces[T](body: => T, rewriteWithColon: Boolean = false): T = inBracesOrIndented(body, rewriteWithColon) - /** part { `separator` part } - */ - def tokenSeparated[T](separator: Int, part: () => T): List[T] = { - val ts = new ListBuffer[T] += part() - while (in.token == separator) { - in.nextToken() - ts += part() + def commaSeparated[T](part: () => T): List[T] = + in.currentRegion.withCommasExpected { + val ts = new ListBuffer[T] += part() + while in.token == COMMA do + in.nextToken() + ts += part() + ts.toList } - ts.toList - } - - def commaSeparated[T](part: () => T): List[T] = tokenSeparated(COMMA, part) def inSepRegion[T](f: Region => Region)(op: => T): T = val cur = in.currentRegion @@ -3766,7 +3759,7 @@ object Parsers { val derived = if (isIdent(nme.derives)) { in.nextToken() - tokenSeparated(COMMA, () => convertToTypeId(qualId())) + commaSeparated(() => convertToTypeId(qualId())) } else Nil possibleTemplateStart() diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index 4a902907278b..892e4db639ab 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -67,6 +67,7 @@ object Scanners { } def isNewLine = token == NEWLINE || token == NEWLINES + def isStatSep = isNewLine || token == SEMI def isIdent = token == IDENTIFIER || token == BACKQUOTED_IDENT def isIdent(name: Name) = token == IDENTIFIER && this.name == name @@ -272,7 +273,40 @@ object Scanners { private val prev = newTokenData /** The current region. This is initially an Indented region with zero indentation width. */ - var currentRegion: Region = Indented(IndentWidth.Zero, Set(), EMPTY, null) + var currentRegion: Region = Indented(IndentWidth.Zero, EMPTY, null) + +// Error recovery ------------------------------------------------------------ + + private def lastKnownIndentWidth: IndentWidth = + def recur(r: Region): IndentWidth = + if r.knownWidth == null then recur(r.enclosing) else r.knownWidth + recur(currentRegion) + + private var skipping = false + + /** Skip on error to next safe point. + */ + def skip(): Unit = + val lastRegion = currentRegion + skipping = true + def atStop = + token == EOF + || (currentRegion eq lastRegion) + && (isStatSep + || closingParens.contains(token) && lastRegion.toList.exists(_.closedBy == token) + || token == COMMA && lastRegion.toList.exists(_.commasExpected) + || token == OUTDENT && indentWidth(offset) < lastKnownIndentWidth) + // stop at OUTDENT if the new indentwidth is smaller than the indent width of + // currentRegion. This corrects for the problem that sometimes we don't see an INDENT + // when skipping and therefore might erroneously end up syncing on a nested OUTDENT. + if debugTokenStream then + println(s"\nSTART SKIP AT ${sourcePos().line + 1}, $this in $currentRegion") + while !atStop do + nextToken() + if debugTokenStream then + println(s"\nSTOP SKIP AT ${sourcePos().line + 1}, $this in $currentRegion") + if token == OUTDENT then dropUntil(_.isInstanceOf[Indented]) + skipping = false // Get next token ------------------------------------------------------------ @@ -303,27 +337,27 @@ object Scanners { nextToken() result + private inline def dropUntil(inline matches: Region => Boolean): Unit = + while !matches(currentRegion) && !currentRegion.isOutermost do + currentRegion = currentRegion.enclosing + def adjustSepRegions(lastToken: Token): Unit = (lastToken: @switch) match { case LPAREN | LBRACKET => currentRegion = InParens(lastToken, currentRegion) case LBRACE => currentRegion = InBraces(currentRegion) case RBRACE => - def dropBraces(): Unit = currentRegion match { - case r: InBraces => - currentRegion = r.enclosing - case _ => - if (!currentRegion.isOutermost) { - currentRegion = currentRegion.enclosing - dropBraces() - } - } - dropBraces() + dropUntil(_.isInstanceOf[InBraces]) + if !currentRegion.isOutermost then currentRegion = currentRegion.enclosing case RPAREN | RBRACKET => currentRegion match { case InParens(prefix, outer) if prefix + 1 == lastToken => currentRegion = outer case _ => } + case OUTDENT => + currentRegion match + case r: Indented => currentRegion = r.enclosing + case _ => case STRINGLIT => currentRegion match { case InString(_, outer) => currentRegion = outer @@ -411,8 +445,8 @@ object Scanners { || { r.outer match case null => true - case Indented(outerWidth, others, _, _) => - outerWidth < nextWidth && !others.contains(nextWidth) + case ro @ Indented(outerWidth, _, _) => + outerWidth < nextWidth && !ro.otherIndentWidths.contains(nextWidth) case outer => outer.indentWidth < nextWidth } @@ -518,6 +552,15 @@ object Scanners { var lastWidth = IndentWidth.Zero var indentPrefix = EMPTY val nextWidth = indentWidth(offset) + + // If nextWidth is an indentation level not yet seen by enclosing indentation + // region, invoke `handler`. + def handleNewIndentWidth(r: Region, handler: Indented => Unit): Unit = r match + case r @ Indented(curWidth, prefix, outer) + if curWidth < nextWidth && !r.otherIndentWidths.contains(nextWidth) && nextWidth != lastWidth => + handler(r) + case _ => + currentRegion match case r: Indented => indentIsSignificant = indentSyntax @@ -546,32 +589,31 @@ object Scanners { else if !isLeadingInfixOperator(nextWidth) && !statCtdTokens.contains(lastToken) && lastToken != INDENT then currentRegion match case r: Indented => - currentRegion = r.enclosing insert(OUTDENT, offset) - case r: InBraces if !closingRegionTokens.contains(token) => - report.warning("Line is indented too far to the left, or a `}` is missing", sourcePos()) - case _ => + if next.token != COLON then + handleNewIndentWidth(r.enclosing, ir => + errorButContinue( + i"""The start of this line does not match any of the previous indentation widths. + |Indentation width of current line : $nextWidth + |This falls between previous widths: ${ir.width} and $lastWidth""")) + case r => + if skipping then + if r.enclosing.isClosedByUndentAt(nextWidth) then + insert(OUTDENT, offset) + else if r.isInstanceOf[InBraces] && !closingRegionTokens.contains(token) then + report.warning("Line is indented too far to the left, or a `}` is missing", sourcePos()) else if lastWidth < nextWidth || lastWidth == nextWidth && (lastToken == MATCH || lastToken == CATCH) && token == CASE then if canStartIndentTokens.contains(lastToken) then - currentRegion = Indented(nextWidth, Set(), lastToken, currentRegion) + currentRegion = Indented(nextWidth, lastToken, currentRegion) insert(INDENT, offset) else if lastToken == SELFARROW then currentRegion.knownWidth = nextWidth else if (lastWidth != nextWidth) errorButContinue(spaceTabMismatchMsg(lastWidth, nextWidth)) - currentRegion match - case Indented(curWidth, others, prefix, outer) - if curWidth < nextWidth && !others.contains(nextWidth) && nextWidth != lastWidth => - if token == OUTDENT && next.token != COLON then - errorButContinue( - i"""The start of this line does not match any of the previous indentation widths. - |Indentation width of current line : $nextWidth - |This falls between previous widths: $curWidth and $lastWidth""") - else - currentRegion = Indented(curWidth, others + nextWidth, prefix, outer) - case _ => + if token != OUTDENT || next.token == COLON then + handleNewIndentWidth(currentRegion, _.otherIndentWidths += nextWidth) end handleNewLine def spaceTabMismatchMsg(lastWidth: IndentWidth, nextWidth: IndentWidth) = @@ -591,7 +633,7 @@ object Scanners { val nextWidth = indentWidth(next.offset) val lastWidth = currentRegion.indentWidth if lastWidth < nextWidth then - currentRegion = Indented(nextWidth, Set(), COLONEOL, currentRegion) + currentRegion = Indented(nextWidth, COLONEOL, currentRegion) offset = next.offset token = INDENT end observeIndented @@ -606,7 +648,6 @@ object Scanners { && !(token == CASE && r.prefix == MATCH) && next.token == EMPTY // can be violated for ill-formed programs, e.g. neg/i12605.sala => - currentRegion = r.enclosing insert(OUTDENT, offset) case _ => @@ -621,9 +662,7 @@ object Scanners { } def closeIndented() = currentRegion match - case r: Indented if !r.isOutermost => - insert(OUTDENT, offset) - currentRegion = r.outer + case r: Indented if !r.isOutermost => insert(OUTDENT, offset) case _ => /** - Join CASE + CLASS => CASECLASS, CASE + OBJECT => CASEOBJECT @@ -654,7 +693,6 @@ object Scanners { currentRegion match case r: Indented if isEnclosedInParens(r.outer) => insert(OUTDENT, offset) - currentRegion = r.outer case _ => lookAhead() if isAfterLineEnd @@ -1488,8 +1526,9 @@ object Scanners { * InBraces a pair of braces { ... } * Indented a pair of ... tokens */ - abstract class Region: - /** The region enclosing this one, or `null` for the outermost region */ + abstract class Region(val closedBy: Token): + + /** The region enclosing this one, or `null` for the outermost region */ def outer: Region | Null /** Is this region the outermost region? */ @@ -1516,6 +1555,37 @@ object Scanners { if enclosing.knownWidth == null then enclosing.useOuterWidth() knownWidth = enclosing.knownWidth + /** Does `width` represent an undent of an enclosing indentation region? + * This is the case if there is an indentation region that goes deeper than `width` + * and that is enclosed in a region that contains `width` as an indentation width. + */ + def isClosedByUndentAt(width: IndentWidth): Boolean = this match + case _: Indented => + !isOutermost && width <= indentWidth && enclosing.coversIndent(width) + case _ => + enclosing.isClosedByUndentAt(width) + + /** A region "covers" an indentation with `width` if it has `width` as known + * indentation width (either as primary, or in case of an Indent region as + * alternate width). + */ + protected def coversIndent(w: IndentWidth): Boolean = + knownWidth != null && w == indentWidth + + private var myCommasExpected: Boolean = false + + inline def withCommasExpected[T](inline op: => T): T = + val saved = myCommasExpected + myCommasExpected = true + val res = op + myCommasExpected = false + res + + def commasExpected = myCommasExpected + + def toList: List[Region] = + this :: (if outer == null then Nil else outer.toList) + private def delimiter = this match case _: InString => "}(in string)" case InParens(LPAREN, _) => ")" @@ -1526,27 +1596,31 @@ object Scanners { /** Show open regions as list of lines with decreasing indentations */ def visualize: String = - indentWidth.toPrefix - + delimiter - + outer.match - case null => "" - case next: Region => "\n" + next.visualize + toList.map(r => s"${r.indentWidth.toPrefix}${r.delimiter}").mkString("\n") + + override def toString: String = + toList.map(r => s"(${r.indentWidth}, ${r.delimiter})").mkString(" in ") end Region - case class InString(multiLine: Boolean, outer: Region) extends Region - case class InParens(prefix: Token, outer: Region) extends Region - case class InBraces(outer: Region) extends Region - case class InCase(outer: Region) extends Region + case class InString(multiLine: Boolean, outer: Region) extends Region(RBRACE) + case class InParens(prefix: Token, outer: Region) extends Region(prefix + 1) + case class InBraces(outer: Region) extends Region(RBRACE) + case class InCase(outer: Region) extends Region(OUTDENT) /** A class describing an indentation region. * @param width The principal indendation width - * @param others Other indendation widths > width of lines in the same region * @param prefix The token before the initial of the region */ - case class Indented(width: IndentWidth, others: Set[IndentWidth], prefix: Token, outer: Region | Null) extends Region: + case class Indented(width: IndentWidth, prefix: Token, outer: Region | Null) extends Region(OUTDENT): knownWidth = width - def topLevelRegion(width: IndentWidth) = Indented(width, Set(), EMPTY, null) + /** Other indendation widths > width of lines in the same region */ + var otherIndentWidths: Set[IndentWidth] = Set() + + override def coversIndent(w: IndentWidth) = width == w || otherIndentWidths.contains(w) + end Indented + + def topLevelRegion(width: IndentWidth) = Indented(width, EMPTY, null) enum IndentWidth { case Run(ch: Char, n: Int) diff --git a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala index 46bb43170bde..1f414e7e912c 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala @@ -287,7 +287,7 @@ object Tokens extends TokensCommon { final val endMarkerTokens = identifierTokens | BitSet(IF, WHILE, FOR, MATCH, TRY, NEW, THROW, GIVEN, VAL, THIS) - final val skipStopTokens = BitSet(SEMI, NEWLINE, NEWLINES, RBRACE, RPAREN, RBRACKET, OUTDENT) + final val closingParens = BitSet(RPAREN, RBRACKET, RBRACE) final val softModifierNames = Set(nme.inline, nme.opaque, nme.open, nme.transparent, nme.infix) } diff --git a/tests/neg/i12605.scala b/tests/neg/i12605.scala index bcd7aedc606b..72d38fac2f5c 100644 --- a/tests/neg/i12605.scala +++ b/tests/neg/i12605.scala @@ -1,4 +1,3 @@ object Foo: def joe(): List[(Int, Int)] = List((2, 3), (3, 4)).filter case (a, b) => b > a // error // error -// error \ No newline at end of file diff --git a/tests/neg/i14507.scala b/tests/neg/i14507.scala new file mode 100644 index 000000000000..6092a3d9d6cd --- /dev/null +++ b/tests/neg/i14507.scala @@ -0,0 +1,8 @@ +class C: + def test = g + def f(b: Boolean): Int = + if b then // error + end if + 42 + def g = 27 +end C \ No newline at end of file diff --git a/tests/neg/i1679.scala b/tests/neg/i1679.scala index cadeb85dc8db..08a33bb15596 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 // error + val x: A[T=Int, T=Int] = ??? // error: ']' expected, but '=' found } diff --git a/tests/neg/i2494.scala b/tests/neg/i2494.scala index fb4d338128fb..a7c2b0c38818 100644 --- a/tests/neg/i2494.scala +++ b/tests/neg/i2494.scala @@ -1,3 +1,2 @@ enum object // error -// error \ No newline at end of file diff --git a/tests/neg/i4373c.scala b/tests/neg/i4373c.scala index c14d69da65d8..ab405a14d29a 100644 --- a/tests/neg/i4373c.scala +++ b/tests/neg/i4373c.scala @@ -1,4 +1,3 @@ // ==> 18b253a4a89a84c5674165c6fc3efafad535eee3.scala <== object x0 { def x1[x2 <:_[ // error -// error \ No newline at end of file diff --git a/tests/neg/i4934.scala b/tests/neg/i4934.scala index 2f9d1fa5e0db..0c7dabeaa1ef 100644 --- a/tests/neg/i4934.scala +++ b/tests/neg/i4934.scala @@ -8,4 +8,4 @@ object Main { object Foo { val a = ""); // error: `}` expected but `)` found -} \ No newline at end of file +} // error: eof expected but `}` found diff --git a/tests/neg/i8731a.scala b/tests/neg/i8731a.scala index c7d230bb686e..94b88e2f6012 100644 --- a/tests/neg/i8731a.scala +++ b/tests/neg/i8731a.scala @@ -7,4 +7,4 @@ object test: for a <- Seq() end for // error: `yield` or `do` expected - do () // error: expression expected but eof found \ No newline at end of file + do () \ No newline at end of file diff --git a/tests/neg/indent.scala b/tests/neg/indent.scala index e6d6550bee19..fc3a065d7e6c 100644 --- a/tests/neg/indent.scala +++ b/tests/neg/indent.scala @@ -4,6 +4,6 @@ object Test { val y3 = if (1) max 10 gt 0 // error: end of statement expected but integer literal found // error // error 1 - else + else // error 2 -} // error \ No newline at end of file +} \ No newline at end of file diff --git a/tests/neg/parser-stability-1.scala b/tests/neg/parser-stability-1.scala index 661ab87e31e5..560b9cf116e3 100644 --- a/tests/neg/parser-stability-1.scala +++ b/tests/neg/parser-stability-1.scala @@ -1,4 +1,3 @@ object x0 { x1 match // error def this // error -// error \ No newline at end of file diff --git a/tests/neg/parser-stability-18.scala b/tests/neg/parser-stability-18.scala index 17a8f19f404a..403d96c0cc49 100644 --- a/tests/neg/parser-stability-18.scala +++ b/tests/neg/parser-stability-18.scala @@ -2,4 +2,3 @@ trait x0 { class x1 (x1:x0 { type x1 <: List[x1 <: // error -// error \ No newline at end of file diff --git a/tests/neg/parser-stability-19.scala b/tests/neg/parser-stability-19.scala index c320c7e8df74..fa643cd9154b 100644 --- a/tests/neg/parser-stability-19.scala +++ b/tests/neg/parser-stability-19.scala @@ -1,5 +1,4 @@ object x0 { case class x0[](): // error def x0( ) ] // error - def x0 ( x0:x0 ):x0.type = x1 x0 // error // error -// error \ No newline at end of file + def x0 ( x0:x0 ):x0.type = x1 x0 diff --git a/tests/neg/parser-stability-2.scala b/tests/neg/parser-stability-2.scala index f485e81fd21e..38fd8f13eaff 100644 --- a/tests/neg/parser-stability-2.scala +++ b/tests/neg/parser-stability-2.scala @@ -1,3 +1,2 @@ trait x0 { new _ // error -// error \ No newline at end of file diff --git a/tests/neg/syntax-error-recovery.check b/tests/neg/syntax-error-recovery.check new file mode 100644 index 000000000000..0bf626210fed --- /dev/null +++ b/tests/neg/syntax-error-recovery.check @@ -0,0 +1,144 @@ +-- [E040] Syntax Error: tests/neg/syntax-error-recovery.scala:3:16 ----------------------------------------------------- +3 | if (x < 0 then // error + | ^^^^ + | ')' expected, but 'then' found +-- [E040] Syntax Error: tests/neg/syntax-error-recovery.scala:11:16 ---------------------------------------------------- +11 | if (x < 0 then // error + | ^^^^ + | ')' expected, but 'then' found +-- [E040] Syntax Error: tests/neg/syntax-error-recovery.scala:19:4 ----------------------------------------------------- +19 | if x == 0 then println(bar) // error + | ^^ + | ')' expected, but 'if' found +-- [E040] Syntax Error: tests/neg/syntax-error-recovery.scala:23:12 ---------------------------------------------------- +23 | if x < 0) then // error + | ^ + | 'then' expected, but ')' found +-- [E040] Syntax Error: tests/neg/syntax-error-recovery.scala:32:16 ---------------------------------------------------- +32 | if (x < 0 then // error + | ^^^^ + | ')' expected, but 'then' found +-- [E040] Syntax Error: tests/neg/syntax-error-recovery.scala:40:16 ---------------------------------------------------- +40 | if (x < 0 then // error + | ^^^^ + | ')' expected, but 'then' found +-- [E040] Syntax Error: tests/neg/syntax-error-recovery.scala:48:4 ----------------------------------------------------- +48 | if x == 0 then println(bar) // error + | ^^ + | ')' expected, but 'if' found +-- [E040] Syntax Error: tests/neg/syntax-error-recovery.scala:52:12 ---------------------------------------------------- +52 | if x < 0) then // error + | ^ + | 'then' expected, but ')' found +-- [E018] Syntax Error: tests/neg/syntax-error-recovery.scala:59:14 ---------------------------------------------------- +59 | foo2(foo2(,) // error // error + | ^ + | expression expected but ',' found + | + | longer explanation available when compiling with `-explain` +-- [E018] Syntax Error: tests/neg/syntax-error-recovery.scala:59:15 ---------------------------------------------------- +59 | foo2(foo2(,) // error // error + | ^ + | expression expected but ')' found + | + | longer explanation available when compiling with `-explain` +-- [E040] Syntax Error: tests/neg/syntax-error-recovery.scala:62:8 ----------------------------------------------------- +62 |// error + | ^ + | ')' expected, but eof found +-- [E006] Not Found Error: tests/neg/syntax-error-recovery.scala:8:10 -------------------------------------------------- +8 | println(bar) // error + | ^^^ + | Not found: bar + | + | longer explanation available when compiling with `-explain` +-- [E006] Not Found Error: tests/neg/syntax-error-recovery.scala:15:10 ------------------------------------------------- +15 | println(baz) // error + | ^^^ + | Not found: baz + | + | longer explanation available when compiling with `-explain` +-- [E006] Not Found Error: tests/neg/syntax-error-recovery.scala:20:10 ------------------------------------------------- +20 | println(bar) // error + | ^^^ + | Not found: bar + | + | longer explanation available when compiling with `-explain` +-- [E006] Not Found Error: tests/neg/syntax-error-recovery.scala:27:10 ------------------------------------------------- +27 | println(bam) // error + | ^^^ + | Not found: bam + | + | longer explanation available when compiling with `-explain` +-- [E006] Not Found Error: tests/neg/syntax-error-recovery.scala:37:10 ------------------------------------------------- +37 | println(bar) // error + | ^^^ + | Not found: bar + | + | longer explanation available when compiling with `-explain` +-- [E006] Not Found Error: tests/neg/syntax-error-recovery.scala:44:10 ------------------------------------------------- +44 | println(baz) // error + | ^^^ + | Not found: baz + | + | longer explanation available when compiling with `-explain` +-- [E006] Not Found Error: tests/neg/syntax-error-recovery.scala:49:10 ------------------------------------------------- +49 | println(bar) // error + | ^^^ + | Not found: bar + | + | longer explanation available when compiling with `-explain` +-- [E006] Not Found Error: tests/neg/syntax-error-recovery.scala:56:10 ------------------------------------------------- +56 | println(bam) // error + | ^^^ + | Not found: bam + | + | longer explanation available when compiling with `-explain` +-- [E006] Not Found Error: tests/neg/syntax-error-recovery.scala:61:10 ------------------------------------------------- +61 | println(bam) // error + | ^^^ + | Not found: bam + | + | longer explanation available when compiling with `-explain` +-- [E129] Potential Issue Warning: tests/neg/syntax-error-recovery.scala:7:2 ------------------------------------------- +6 | 2 +7 | } + | ^ + | A pure expression does nothing in statement position; you may be omitting necessary parentheses + | + | longer explanation available when compiling with `-explain` +-- [E129] Potential Issue Warning: tests/neg/syntax-error-recovery.scala:15:2 ------------------------------------------ +14 | 2 +15 | println(baz) // error + | ^ + | A pure expression does nothing in statement position; you may be omitting necessary parentheses + | + | longer explanation available when compiling with `-explain` +-- [E129] Potential Issue Warning: tests/neg/syntax-error-recovery.scala:27:2 ------------------------------------------ +26 | 2 +27 | println(bam) // error + | ^ + | A pure expression does nothing in statement position; you may be omitting necessary parentheses + | + | longer explanation available when compiling with `-explain` +-- [E129] Potential Issue Warning: tests/neg/syntax-error-recovery.scala:36:2 ------------------------------------------ +35 | 2 +36 | } + | ^ + | A pure expression does nothing in statement position; you may be omitting necessary parentheses + | + | longer explanation available when compiling with `-explain` +-- [E129] Potential Issue Warning: tests/neg/syntax-error-recovery.scala:44:2 ------------------------------------------ +43 | 2 +44 | println(baz) // error + | ^ + | A pure expression does nothing in statement position; you may be omitting necessary parentheses + | + | longer explanation available when compiling with `-explain` +-- [E129] Potential Issue Warning: tests/neg/syntax-error-recovery.scala:56:2 ------------------------------------------ +55 | 2 +56 | println(bam) // error + | ^ + | A pure expression does nothing in statement position; you may be omitting necessary parentheses + | + | longer explanation available when compiling with `-explain` diff --git a/tests/neg/syntax-error-recovery.scala b/tests/neg/syntax-error-recovery.scala new file mode 100644 index 000000000000..775abeb97bdb --- /dev/null +++ b/tests/neg/syntax-error-recovery.scala @@ -0,0 +1,62 @@ +object Test { + def foo(x: Int) = { + if (x < 0 then // error + 1 + else + 2 + } + println(bar) // error + + def foo2(x: Int) = + if (x < 0 then // error + 1 + else + 2 + println(baz) // error + + def foo3(x: Int) = + foo2(x + if x == 0 then println(bar) // error + println(bar) // error + + def foo4(x: Int) = + if x < 0) then // error + 1 + else + 2 + println(bam) // error + +} +object Test2: + def foo(x: Int) = { + if (x < 0 then // error + 1 + else + 2 + } + println(bar) // error + + def foo2(x: Int) = + if (x < 0 then // error + 1 + else + 2 + println(baz) // error + + def foo3(x: Int) = + foo2(x + if x == 0 then println(bar) // error + println(bar) // error + + def foo4(x: Int) = + if x < 0) then // error + 1 + else + 2 + println(bam) // error + + def foo5(x: Int) = + foo2(foo2(,) // error // error + + println(bam) // error +// error \ No newline at end of file diff --git a/tests/neg/t6810.check b/tests/neg/t6810.check index 147081e0daf5..55f9f7ca2443 100644 --- a/tests/neg/t6810.check +++ b/tests/neg/t6810.check @@ -22,11 +22,3 @@ 30 | val b = ' | ^ | unclosed character literal --- Warning: tests/neg/t6810.scala:6:0 ---------------------------------------------------------------------------------- -6 |' // but not embedded EOL sequences not represented as escapes - |^ - |Line is indented too far to the left, or a `}` is missing --- Warning: tests/neg/t6810.scala:31:0 --------------------------------------------------------------------------------- -31 |' // anypos-error CR seen as EOL by scanner; FSR, error only on open quote, unlike `y` - |^ - |Line is indented too far to the left, or a `}` is missing