From 8869b047ab85cb0a823841a33962afb56c6be251 Mon Sep 17 00:00:00 2001 From: Lucy Martin Date: Thu, 28 Mar 2024 10:33:20 +0000 Subject: [PATCH] Extra check to avoid converting block expressions on the rhs of a symbolic infix expression. Tests added for: * Original cast as per the ticket should not be changed * Similar match statement that should update * Code blocks in this position, as opposed to a partial function, cant update here * Simple change that should apply but in a code position where the op stack is nonempty * Equivalent code, but passing in the partial function as a single parameter, again, not updating [Cherry-picked 43d33a008a233b691c0c6697908424ba35c3c876] --- .../dotty/tools/dotc/parsing/Parsers.scala | 22 ++++++- .../dotty/tools/dotc/CompilationTests.scala | 1 + tests/rewrites/i20002.check | 51 +++++++++++++++ tests/rewrites/i20002.scala | 62 +++++++++++++++++++ 4 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 tests/rewrites/i20002.check create mode 100644 tests/rewrites/i20002.scala diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 8525c35f035f..a6521bb870b8 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -794,6 +794,8 @@ object Parsers { * 6. the opening brace does not follow a `=>`. The reason for this condition is that * 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). + * 7. not a code block being the input to a direct symbolic function call `inst method {\n expr \n}` cannot + * become `inst method :\n expr` for a fully symbolic method */ def bracesToIndented[T](body: => T, rewriteWithColon: Boolean): T = { val underColonSyntax = possibleColonOffset == in.lastOffset @@ -807,10 +809,28 @@ object Parsers { } var canRewrite = allBraces(in.currentRegion) && // test (1) !testChars(in.lastOffset - 3, " =>") // test(6) + + def isStartOfSymbolicFunction: Boolean = + opStack.headOption.exists { x => + val bq = x.operator.isBackquoted + val op = x.operator.name.toSimpleName.decode.forall { + Chars.isOperatorPart + } + val loc = startOpening < x.offset && x.offset < endOpening + val res = !bq && op && loc + res + } val t = enclosed(LBRACE, { canRewrite &= in.isAfterLineEnd // test (2) val curOffset = in.offset - try body + try { + val bodyResolved = body + bodyResolved match + case x:(Match | Block) => + canRewrite &= !isStartOfSymbolicFunction // test (7) + case _ => + bodyResolved + } finally { canRewrite &= in.isAfterLineEnd && in.offset != curOffset // test (3)(4) } diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index 38d43116566d..4f7d3fc3f241 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -66,6 +66,7 @@ class CompilationTests { compileFile("tests/rewrites/i12340.scala", unindentOptions.and("-rewrite")), compileFile("tests/rewrites/i17187.scala", unindentOptions.and("-rewrite")), compileFile("tests/rewrites/i17399.scala", unindentOptions.and("-rewrite")), + compileFile("tests/rewrites/i20002.scala", defaultOptions.and("-indent", "-rewrite")), ).checkRewrites() } diff --git a/tests/rewrites/i20002.check b/tests/rewrites/i20002.check new file mode 100644 index 000000000000..70c9411eb4b2 --- /dev/null +++ b/tests/rewrites/i20002.check @@ -0,0 +1,51 @@ +object Reactions: + def main: Unit = + Reactions += { + case 0 => + case 1 => + } + + Reactions run: + case 0 => + case 1 => + + Reactions run_+ : + case 0 => + case 1 => + + Reactions `+=`: + case 0 => + case 1 => + + def bar: Int = ??? + + bar match + case 0 => + case 1 => + + def partPartial(i: Int): PartialFunction[Int, Unit] = + case `i` => + + Reactions += { + val pp1 = partPartial(1) + val pp2 = partPartial(2) + def codeBlock = + ??? + ??? + pp1 orElse pp2 + } + + val partialFunction = partPartial(1) orElse partPartial(2) + Reactions += { + partialFunction + } + + def +=(f: PartialFunction[Int, Unit]) = + ??? + + def run (f: PartialFunction[Int, Unit]) = + ??? + + def run_+ (f: PartialFunction[Int, Unit]) = + ??? + diff --git a/tests/rewrites/i20002.scala b/tests/rewrites/i20002.scala new file mode 100644 index 000000000000..56ea023b63b0 --- /dev/null +++ b/tests/rewrites/i20002.scala @@ -0,0 +1,62 @@ +object Reactions { + def main: Unit = { + Reactions += { + case 0 => + case 1 => + } + + Reactions run { + case 0 => + case 1 => + } + + Reactions run_+ { + case 0 => + case 1 => + } + + Reactions `+=` { + case 0 => + case 1 => + } + + def bar: Int = ??? + + bar match { + case 0 => + case 1 => + } + + def partPartial(i: Int): PartialFunction[Int, Unit] = { + case `i` => + } + + Reactions += { + val pp1 = partPartial(1) + val pp2 = partPartial(2) + def codeBlock = { + ??? + ??? + } + pp1 orElse pp2 + } + + val partialFunction = partPartial(1) orElse partPartial(2) + Reactions += { + partialFunction + } + } + + def +=(f: PartialFunction[Int, Unit]) = { + ??? + } + + def run (f: PartialFunction[Int, Unit]) = { + ??? + } + + def run_+ (f: PartialFunction[Int, Unit]) = { + ??? + } + +}