From 5a274b1ecd4b42a7b0464adc18e7fd1d6da5338f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 19 May 2020 13:26:45 +0200 Subject: [PATCH 1/2] Fix #8982: Insert colons when rewriting classes to indentation syntax Allow `for {` under -new-syntax --- .../dotty/tools/dotc/parsing/Parsers.scala | 31 ++++++++++--------- tests/pos/i8982.scala | 14 +++++++++ 2 files changed, 30 insertions(+), 15 deletions(-) create mode 100644 tests/pos/i8982.scala diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 24736ab0ef3e..14b40037b875 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -573,7 +573,7 @@ object Parsers { def inBraces[T](body: => T): T = enclosed(LBRACE, body) def inBrackets[T](body: => T): T = enclosed(LBRACKET, body) - def inBracesOrIndented[T](body: => T): T = + def inBracesOrIndented[T](body: => T, rewriteWithColon: Boolean = false): T = if (in.token == INDENT) { val rewriteToBraces = in.rewriteNoIndent && @@ -582,12 +582,12 @@ object Parsers { else enclosed(INDENT, body) } else - if (in.rewriteToIndent) bracesToIndented(body) + if (in.rewriteToIndent) bracesToIndented(body, rewriteWithColon) else inBraces(body) - def inDefScopeBraces[T](body: => T): T = { + def inDefScopeBraces[T](body: => T, rewriteWithColon: Boolean = false): T = { val saved = lastStatOffset - try inBracesOrIndented(body) + try inBracesOrIndented(body, rewriteWithColon) finally lastStatOffset = saved } @@ -775,8 +775,9 @@ object Parsers { * rewriting back to braces does not work after `=>` (since in most cases braces are omitted * after a `=>` it would be annoying if braces were inserted). */ - def bracesToIndented[T](body: => T): T = { - val colonRequired = possibleColonOffset == in.lastOffset + def bracesToIndented[T](body: => T, rewriteWithColon: Boolean): T = { + val underColonSyntax = possibleColonOffset == in.lastOffset + val colonRequired = rewriteWithColon || underColonSyntax val (startOpening, endOpening) = startingElimRegion(colonRequired) val isOutermost = in.currentRegion.isOutermost def allBraces(r: Region): Boolean = r match { @@ -795,10 +796,10 @@ object Parsers { } }) canRewrite &= (in.isAfterLineEnd || statCtdTokens.contains(in.token)) // test (5) - if (canRewrite && (!colonRequired || in.colonSyntax)) { + if (canRewrite && (!underColonSyntax || in.colonSyntax)) { val openingPatchStr = - if (!colonRequired) "" - else if (testChar(startOpening - 1, Chars.isOperatorPart(_))) " :" + if !colonRequired then "" + else if testChar(startOpening - 1, Chars.isOperatorPart(_)) then " :" else ":" val (startClosing, endClosing) = closingElimRegion() patch(source, Span(startOpening, endOpening), openingPatchStr) @@ -1736,7 +1737,8 @@ object Parsers { /** Refinement ::= `{' RefineStatSeq `}' */ - def refinement(): List[Tree] = inBracesOrIndented(refineStatSeq()) + def refinement(): List[Tree] = + inBracesOrIndented(refineStatSeq(), rewriteWithColon = true) /** TypeBounds ::= [`>:' Type] [`<:' Type] */ @@ -2469,11 +2471,10 @@ object Parsers { val pos = t.sourcePos pos.startLine < pos.endLine } - if (rewriteToNewSyntax(Span(start)) && (leading == LBRACE || !hasMultiLineEnum)) { + if in.newSyntax && in.rewrite && (leading == LBRACE || !hasMultiLineEnum) then // Don't rewrite if that could change meaning of newlines newLinesOpt() dropParensOrBraces(start, if (in.token == YIELD || in.token == DO) "" else "do") - } } in.observeIndented() res @@ -3687,7 +3688,7 @@ object Parsers { Template(constr, parents, derived, self, stats) def templateBody(): (ValDef, List[Tree]) = - val r = inDefScopeBraces { templateStatSeq() } + val r = inDefScopeBraces(templateStatSeq(), rewriteWithColon = true) if in.token == WITH then syntaxError(EarlyDefinitionsNotSupported()) in.nextToken() @@ -3706,7 +3707,7 @@ object Parsers { def packaging(start: Int): Tree = val pkg = qualId() possibleTemplateStart() - val stats = inDefScopeBraces(topStatSeq()) + val stats = inDefScopeBraces(topStatSeq(), rewriteWithColon = true) makePackaging(start, pkg, stats) /** TopStatSeq ::= TopStat {semi TopStat} @@ -3898,7 +3899,7 @@ object Parsers { if in.token == EOF then ts += makePackaging(start, pkg, List()) else if in.isNestedStart then - ts += inDefScopeBraces(makePackaging(start, pkg, topStatSeq())) + ts += inDefScopeBraces(makePackaging(start, pkg, topStatSeq()), rewriteWithColon = true) continue = true else acceptStatSep() diff --git a/tests/pos/i8982.scala b/tests/pos/i8982.scala new file mode 100644 index 000000000000..1408fadfe7bb --- /dev/null +++ b/tests/pos/i8982.scala @@ -0,0 +1,14 @@ + +object Foo { + def bar(x: Int): Unit = { + println(x) + } +} + +class Baz(n: Int) { + def printRepeat(repeat: Int) = { + for { + x <- 1 to repeat + } println(s"$x - ${n * x}") + } +} From a433f5c48170212ae2f107c13c941539fc2c4900 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 19 May 2020 14:38:59 +0200 Subject: [PATCH 2/2] Unrelated test --- tests/run/rainwater.check | 1 + tests/run/rainwater.scala | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 tests/run/rainwater.check create mode 100644 tests/run/rainwater.scala diff --git a/tests/run/rainwater.check b/tests/run/rainwater.check new file mode 100644 index 000000000000..267030eab27a --- /dev/null +++ b/tests/run/rainwater.check @@ -0,0 +1 @@ +rainWater captured by List(0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1) = 6 diff --git a/tests/run/rainwater.scala b/tests/run/rainwater.scala new file mode 100644 index 000000000000..8b81902b1360 --- /dev/null +++ b/tests/run/rainwater.scala @@ -0,0 +1,21 @@ + +def rainWater(vec: List[Int]): Int = + if vec.isEmpty then 0 + else + val mx = vec.max + val split = vec.indexWhere(_ == mx) + rainWater1(0, vec.take(split + 1)) + + rainWater1(0, vec.drop(split).reverse) + +def rainWater1(mx: Int, xs: List[Int]): Int = xs match + case x :: rest => + val newMx = x max mx + newMx - x + rainWater1(newMx, rest) + case _ => + 0 + +def test(xs: Int*) = + println(s"rainWater captured by ${xs.toList} = ${rainWater(xs.toList)}") + +@main def Test = + test(0,1,0,2,1,0,1,3,2,1,2,1)