From b71066aeda345b583fbcc5c9e6055662622382da Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Sat, 15 Feb 2025 14:32:39 -0800 Subject: [PATCH 1/3] Allow observing an indent after conditional Normally do not infer NEWLINE within parens, but special case old syntax for conditionals, so that it can observe indented syntax. The mechanism is to inject an Indented region when parsing a parenthesized condition which is within an InParens region, such as an arg list. The effect is not to advance past EOL after `(true)`. [Cherry-picked 4ba89e9e8eb027b2bd11503e3621fa5e62e7bad0] --- .../dotty/tools/dotc/parsing/Parsers.scala | 9 +++- tests/pos/i22608.scala | 48 +++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 tests/pos/i22608.scala diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 4354be9662be..63acae33be43 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -97,6 +97,9 @@ object Parsers { private val InCase: Region => Region = Scanners.InCase(_) private val InCond: Region => Region = Scanners.InParens(LPAREN, _) private val InFor : Region => Region = Scanners.InBraces(_) + private val InBrk : Region => Region = _.match + case p: Scanners.InParens => Scanners.Indented(p.indentWidth, p.prefix, p) + case r => r abstract class ParserCommon(val source: SourceFile)(using Context) { @@ -2129,8 +2132,10 @@ object Parsers { def condExpr(altToken: Token): Tree = val t: Tree = if in.token == LPAREN then - var t: Tree = atSpan(in.offset): - makeTupleOrParens(inParensWithCommas(commaSeparated(exprInParens))) + var t: Tree = + inSepRegion(InBrk): // allow inferred NEWLINE for observeIndented below + atSpan(in.offset): + makeTupleOrParens(inParensWithCommas(commaSeparated(exprInParens))) if in.token != altToken then if toBeContinued(altToken) then t = inSepRegion(InCond) { diff --git a/tests/pos/i22608.scala b/tests/pos/i22608.scala new file mode 100644 index 000000000000..e4b49e87769f --- /dev/null +++ b/tests/pos/i22608.scala @@ -0,0 +1,48 @@ + +def f(i: Int) = i +def g(i: Int, j: Int) = i+j + +def t = + val y = f( + if (true)// then + val x = 1 + 5 + else 7 + ) + y + +def u(j: Int) = + val y = g( + if (true)// then + val x = 1 + 5 + else 7, + j + ) + y + +def b(k: Boolean): Int = + f( + if ( + k + && b(!k) > 0 + ) then 27 + else 42 + ) + +def p(b: Boolean) = + import collection.mutable.ListBuffer + val xs, ys = ListBuffer.empty[String] + (if (b) + xs + else + ys) += "hello, world" + (xs.toString, ys.toString) + +def q(b: Boolean) = + import collection.mutable.ListBuffer + val xs, ys = ListBuffer.empty[String] + (if (b) + then xs + else ys) += "hello, world" + (xs.toString, ys.toString) From 1e9068ebd39aa13e998b8bdb7491928d500c5cec Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Sun, 16 Feb 2025 08:49:08 -0800 Subject: [PATCH 2/3] Prefer chaining, avoid duplication in finally [Cherry-picked c8131c031a644c2f9d0dcd9f5fb9f07889880657] --- .../dotty/tools/dotc/parsing/Parsers.scala | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 63acae33be43..2a2acc84d7b4 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -97,7 +97,7 @@ object Parsers { private val InCase: Region => Region = Scanners.InCase(_) private val InCond: Region => Region = Scanners.InParens(LPAREN, _) private val InFor : Region => Region = Scanners.InBraces(_) - private val InBrk : Region => Region = _.match + private val InBrk : Region => Region = case p: Scanners.InParens => Scanners.Indented(p.indentWidth, p.prefix, p) case r => r @@ -2132,27 +2132,25 @@ object Parsers { def condExpr(altToken: Token): Tree = val t: Tree = if in.token == LPAREN then - var t: Tree = - inSepRegion(InBrk): // allow inferred NEWLINE for observeIndented below - atSpan(in.offset): - makeTupleOrParens(inParensWithCommas(commaSeparated(exprInParens))) - if in.token != altToken then - if toBeContinued(altToken) then - t = inSepRegion(InCond) { + inSepRegion(InBrk): // allow inferred NEWLINE for observeIndented below + atSpan(in.offset): + makeTupleOrParens(inParensWithCommas(commaSeparated(exprInParens))) + .pipe: t => + if in.token == altToken then t + else if toBeContinued(altToken) then + inSepRegion(InCond): expr1Rest( postfixExprRest( simpleExprRest(t, Location.ElseWhere), Location.ElseWhere), Location.ElseWhere) - } else if rewriteToNewSyntax(t.span) then - dropParensOrBraces(t.span.start, s"${tokenString(altToken)}") + dropParensOrBraces(t.span.start, tokenString(altToken)) in.observeIndented() return t - t else if in.isNestedStart then - try expr() finally newLinesOpt() + expr().tap(_ => newLinesOpt()) else inSepRegion(InCond)(expr()) if rewriteToOldSyntax(t.span.startPos) then revertToParens(t) From bb8eb471d423e98b629216fbca54f4ce90d28f85 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Tue, 18 Feb 2025 09:18:01 -0800 Subject: [PATCH 3/3] Clarify region workaround [Cherry-picked a19c14ad704c4d1d2e2e794c888fecf8672b0797] --- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 2a2acc84d7b4..47389fbce054 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -97,7 +97,7 @@ object Parsers { private val InCase: Region => Region = Scanners.InCase(_) private val InCond: Region => Region = Scanners.InParens(LPAREN, _) private val InFor : Region => Region = Scanners.InBraces(_) - private val InBrk : Region => Region = + private val InOldCond: Region => Region = // old-style Cond to allow indent when InParens, see #22608 case p: Scanners.InParens => Scanners.Indented(p.indentWidth, p.prefix, p) case r => r @@ -2132,7 +2132,7 @@ object Parsers { def condExpr(altToken: Token): Tree = val t: Tree = if in.token == LPAREN then - inSepRegion(InBrk): // allow inferred NEWLINE for observeIndented below + inSepRegion(InOldCond): // allow inferred NEWLINE for observeIndented below atSpan(in.offset): makeTupleOrParens(inParensWithCommas(commaSeparated(exprInParens))) .pipe: t =>