From 7a578677d516486d3b96eafba32fd1e3951df148 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Fri, 16 Aug 2024 09:03:21 -0700 Subject: [PATCH] Undo patch of double-block apply If `f{}{}` is candidate for rewrite, unpatch it. We don't know exact spans, so just check endpoints to remove. --- .../src/dotty/tools/dotc/parsing/Parsers.scala | 8 +++++++- .../dotty/tools/dotc/rewrites/Rewrites.scala | 17 ++++++++++++++++- .../dotty/tools/dotc/CompilationTests.scala | 1 + tests/rewrites/i21382.scala | 8 ++++++++ 4 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 tests/rewrites/i21382.scala diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 2e441553689c..6aa55a61dc2b 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -27,7 +27,7 @@ import ScriptParsers.* import Decorators.* import util.Chars import scala.annotation.tailrec -import rewrites.Rewrites.{patch, overlapsPatch} +import rewrites.Rewrites.{overlapsPatch, patch, unpatch} import reporting.* import config.Feature import config.Feature.{sourceVersion, migrateTo3} @@ -2779,6 +2779,12 @@ object Parsers { simpleExprRest(tapp, location, canApply = true) case LPAREN | LBRACE | INDENT if canApply => val app = atSpan(startOffset(t), in.offset) { mkApply(t, argumentExprs()) } + if in.rewriteToIndent then + app match + case Apply(Apply(_, List(Block(_, _))), List(blk @ Block(_, _))) => + unpatch(blk.srcPos.sourcePos.source, Span(blk.span.start, blk.span.start + 1)) + unpatch(blk.srcPos.sourcePos.source, Span(blk.span.end, blk.span.end + 1)) + case _ => simpleExprRest(app, location, canApply = true) case USCORE => atSpan(startOffset(t), in.skipToken()) { PostfixOp(t, Ident(nme.WILDCARD)) } diff --git a/compiler/src/dotty/tools/dotc/rewrites/Rewrites.scala b/compiler/src/dotty/tools/dotc/rewrites/Rewrites.scala index 305f61dfa177..ebc50059a39e 100644 --- a/compiler/src/dotty/tools/dotc/rewrites/Rewrites.scala +++ b/compiler/src/dotty/tools/dotc/rewrites/Rewrites.scala @@ -32,11 +32,16 @@ object Rewrites { case class ActionPatch(srcPos: SourcePosition, replacement: String) private class Patches(source: SourceFile) { - private[Rewrites] val pbuf = new mutable.ListBuffer[Patch]() + private[Rewrites] val pbuf = mutable.ListBuffer.empty[Patch] def addPatch(span: Span, replacement: String): Unit = pbuf += Patch(span, replacement) + // remove patches which match either end point + def removePatch(span: Span): Unit = + def p(other: Span): Boolean = span.start == other.start || span.end == other.end + pbuf.filterInPlace(x => !p(x.span)) + def apply(cs: Array[Char]): Array[Char] = { val delta = pbuf.map(_.delta).sum val patches = pbuf.toList.sortBy(_.span.start) @@ -87,6 +92,16 @@ object Rewrites { def patch(span: Span, replacement: String)(using Context): Unit = patch(ctx.compilationUnit.source, span, replacement) + /** Delete patches matching the given span, + * where a match has the same start or end offset. + */ + def unpatch(source: SourceFile, span: Span)(using Context): Unit = + if ctx.reporter != Reporter.NoReporter // NoReporter is used for syntax highlighting + then ctx.settings.rewrite.value.foreach: rewrites => + rewrites.patched + .get(source) + .foreach(_.removePatch(span)) + /** Does `span` overlap with a patch region of `source`? */ def overlapsPatch(source: SourceFile, span: Span)(using Context): Boolean = ctx.settings.rewrite.value.exists(rewrites => diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index 3bd3b5138fad..9aa533bed0e4 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -80,6 +80,7 @@ class CompilationTests { compileDir("tests/rewrites/annotation-named-pararamters", defaultOptions.and("-rewrite", "-source:3.6-migration")), compileFile("tests/rewrites/i21418.scala", unindentOptions.and("-rewrite", "-source:3.5-migration")), compileFile("tests/rewrites/infix-named-args.scala", defaultOptions.and("-rewrite", "-source:3.6-migration")), + compileFile("tests/rewrites/i21382.scala", defaultOptions.and("-indent", "-rewrite")), ).checkRewrites() } diff --git a/tests/rewrites/i21382.scala b/tests/rewrites/i21382.scala new file mode 100644 index 000000000000..75f4007be218 --- /dev/null +++ b/tests/rewrites/i21382.scala @@ -0,0 +1,8 @@ +def check(element: Any)(expected: String): Unit = ??? + +def test = + check { + ??? + }{ + 42.toString + }