Skip to content

Commit f66e5c5

Browse files
authored
Merge pull request #349 from scala/backport-lts-3.3-22855
Backport "Check trailing blank line at EOF for OUTDENT" to 3.3 LTS
2 parents eea671f + f143d1d commit f66e5c5

File tree

3 files changed

+26
-3
lines changed

3 files changed

+26
-3
lines changed

compiler/src/dotty/tools/dotc/parsing/Scanners.scala

+15-2
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,20 @@ object Scanners {
601601
lastWidth = r.knownWidth
602602
newlineIsSeparating = r.isInstanceOf[InBraces]
603603

604+
// can emit OUTDENT if line is not non-empty blank line at EOF
605+
inline def isTrailingBlankLine: Boolean =
606+
token == EOF && {
607+
val end = buf.length - 1 // take terminal NL as empty last line
608+
val prev = buf.lastIndexWhere(!isWhitespace(_), end = end)
609+
prev < 0 || end - prev > 0 && isLineBreakChar(buf(prev))
610+
}
611+
612+
inline def canDedent: Boolean =
613+
lastToken != INDENT
614+
&& !isLeadingInfixOperator(nextWidth)
615+
&& !statCtdTokens.contains(lastToken)
616+
&& !isTrailingBlankLine
617+
604618
if newlineIsSeparating
605619
&& canEndStatTokens.contains(lastToken)
606620
&& canStartStatTokens.contains(token)
@@ -613,9 +627,8 @@ object Scanners {
613627
|| nextWidth == lastWidth && (indentPrefix == MATCH || indentPrefix == CATCH) && token != CASE then
614628
if currentRegion.isOutermost then
615629
if nextWidth < lastWidth then currentRegion = topLevelRegion(nextWidth)
616-
else if !isLeadingInfixOperator(nextWidth) && !statCtdTokens.contains(lastToken) && lastToken != INDENT then
630+
else if canDedent then
617631
currentRegion match
618-
case _ if token == EOF => // no OUTDENT at EOF
619632
case r: Indented =>
620633
insert(OUTDENT, offset)
621634
handleNewIndentWidth(r.enclosing, ir =>

compiler/src/dotty/tools/dotc/util/Chars.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ object Chars:
5050
}
5151

5252
/** Is character a whitespace character (but not a new line)? */
53-
def isWhitespace(c: Char): Boolean =
53+
inline def isWhitespace(c: Char): Boolean =
5454
c == ' ' || c == '\t' || c == CR
5555

5656
/** Can character form part of a doc comment variable $xxx? */

compiler/test/dotty/tools/repl/ReplCompilerTests.scala

+10
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,16 @@ class ReplCompilerTests extends ReplTest:
400400
assertTrue(all.head.startsWith("-- [E103] Syntax Error"))
401401
assertTrue(all.exists(_.trim().startsWith("| Illegal start of statement: this modifier is not allowed here")))
402402

403+
@Test def `i22844 regression colon eol`: Unit = initially:
404+
run:
405+
"""|println:
406+
| "hello, world"
407+
|""".stripMargin // outdent, but this test does not exercise the bug
408+
assertEquals(List("hello, world"), lines())
409+
410+
@Test def `i22844b regression colon arrow eol`: Unit = contextually:
411+
assertTrue(ParseResult.isIncomplete("List(42).map: x =>"))
412+
403413
object ReplCompilerTests:
404414

405415
private val pattern = Pattern.compile("\\r[\\n]?|\\n");

0 commit comments

Comments
 (0)