Repository: scalameta/scalameta (scala)

Issue:
Parser fails when multiline and one condition wrapped in parenthesis
I was trying to fix it, but it touches whitespace issues which I am not super confident about:
```

  test("issue-metals") {
    runTestAssert(
      """|
         |for (m <- decls
         |    if oneCond
         |      && (cond)
         |      && satisfiable) {}
         |
         |""".stripMargin,
      Some("for (m <- decls; if oneCond && cond && satisfiable) {}")
    )(Term.For(
      List(
        Enumerator.Generator(Pat.Var(Term.Name("m")), Term.Name("decls")),
        Enumerator.Guard(Term.ApplyInfix(
          Term.ApplyInfix(
            Term.Name("oneCond"),
            Term.Name("&&"),
            Type.ArgClause(Nil),
            Term.ArgClause(List(Term.Name("cond")), None)
          ),
          Term.Name("&&"),
          Type.ArgClause(Nil),
          Term.ArgClause(List(Term.Name("satisfiable")), None)
        ))
      ),
      Term.Block(Nil)
    ))
  }
```

Pull request:
Fixes #3713. This undoes #3688 as incorrectly reported.

Patch:
diff --git a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScannerTokens.scala b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScannerTokens.scala
index c98cbaad93..30df387ce5 100644
--- a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScannerTokens.scala
+++ b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScannerTokens.scala
@@ -647,7 +647,6 @@ final class ScannerTokens(val tokens: Tokens)(implicit dialect: Dialect) {
           case RegionTry :: xs
               if !next.isAny[KwCatch, KwFinally] && isLeadingInfix != LeadingInfix.Yes => strip(xs)
           case Nil | (_: CanProduceLF) :: _ => Some(rs)
-          case RegionParen :: RegionForParens :: _ => Some(rs)
           case _ => None
         }
         val ok = lastNewlinePos >= 0 && mightStartStat(next, closeDelimOK = true) &&
@@ -657,7 +656,7 @@ final class ScannerTokens(val tokens: Tokens)(implicit dialect: Dialect) {
 
       // https://dotty.epfl.ch/docs/reference/changed-features/operators.html#syntax-change-1
       lazy val isLeadingInfix = sepRegionsOrig match {
-        case Nil | (_: CanProduceLF) :: _ | RegionParen :: RegionForParens :: _
+        case Nil | (_: CanProduceLF) :: _
             if !newlines && lastNewlinePos >= 0 && dialect.allowInfixOperatorAfterNL &&
               next.isSymbolicInfixOperator => isLeadingInfixArg(nextPos + 1, nextIndent)
         case _ => LeadingInfix.No


Test patch:
diff --git a/tests/shared/src/test/scala/scala/meta/tests/parsers/TermSuite.scala b/tests/shared/src/test/scala/scala/meta/tests/parsers/TermSuite.scala
index 52fd157356..5662156a66 100644
--- a/tests/shared/src/test/scala/scala/meta/tests/parsers/TermSuite.scala
+++ b/tests/shared/src/test/scala/scala/meta/tests/parsers/TermSuite.scala
@@ -1341,16 +1341,10 @@ class TermSuite extends ParseSuite {
                   |  if a === b
                   |) yield a
                   |""".stripMargin
-    val layout = "for (a <- fooa; b <- foob; if a === b) yield a"
-    val tree = Term.ForYield(
-      List(
-        Enumerator.Generator(Pat.Var(tname("a")), tname("fooa")),
-        Enumerator.Generator(Pat.Var(tname("b")), tname("foob")),
-        Enumerator.Guard(Term.ApplyInfix(tname("a"), tname("==="), Nil, List(tname("b"))))
-      ),
-      tname("a")
-    )
-    runTestAssert[Term](code, layout)(tree)
+    val error = """|<input>:3: error: `)` expected but `<-` found
+                   |  b <- foob
+                   |    ^""".stripMargin
+    runTestError[Term](code, error)
   }
 
   test("scalafmt #3911 for in parens, NL after `(`, `;` between") {
@@ -1377,16 +1371,10 @@ class TermSuite extends ParseSuite {
                   |     b <- foob
                   |     if a === b) yield a
                   |""".stripMargin
-    val layout = "for (a <- fooa; b <- foob; if a === b) yield a"
-    val tree = Term.ForYield(
-      List(
-        Enumerator.Generator(Pat.Var(tname("a")), tname("fooa")),
-        Enumerator.Generator(Pat.Var(tname("b")), tname("foob")),
-        Enumerator.Guard(Term.ApplyInfix(tname("a"), tname("==="), Nil, List(tname("b"))))
-      ),
-      tname("a")
-    )
-    runTestAssert[Term](code, layout)(tree)
+    val error = """|<input>:2: error: `)` expected but `<-` found
+                   |     b <- foob
+                   |       ^""".stripMargin
+    runTestError[Term](code, error)
   }
 
   test("scalafmt #3911 for in parens, no NL after `(`, `;` between") {
@@ -1436,4 +1424,27 @@ class TermSuite extends ParseSuite {
     runTestAssert[Term](code, layout)(tree)
   }
 
+  test("#3713 cond in parens within enums") {
+    val code = """|for (m <- decls
+                  |    if oneCond
+                  |      && (cond)
+                  |      && satisfiable) {}
+                  |
+                  |""".stripMargin
+    val layout = "for (m <- decls; if oneCond && cond && satisfiable) {}"
+    val tree = Term.For(
+      List(
+        Enumerator.Generator(Pat.Var(tname("m")), tname("decls")),
+        Enumerator.Guard(Term.ApplyInfix(
+          Term.ApplyInfix(tname("oneCond"), tname("&&"), Nil, List(tname("cond"))),
+          tname("&&"),
+          Nil,
+          List(tname("satisfiable"))
+        ))
+      ),
+      blk()
+    )
+    runTestAssert[Stat](code, layout)(tree)
+  }
+
 }
diff --git a/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/ControlSyntaxSuite.scala b/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/ControlSyntaxSuite.scala
index 32be8fd275..06bcb167b3 100644
--- a/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/ControlSyntaxSuite.scala
+++ b/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/ControlSyntaxSuite.scala
@@ -1148,7 +1148,7 @@ class ControlSyntaxSuite extends BaseDottySuite {
     ))
   }
 
-  test("#3713 code in parens within enums") {
+  test("#3713 cond in parens within enums") {
     val code = """|for (m <- decls
                   |    if oneCond
                   |      && (cond)
@@ -1158,20 +1158,15 @@ class ControlSyntaxSuite extends BaseDottySuite {
     val layout = "for (m <- decls; if oneCond && cond && satisfiable) {}"
     val tree = Term.For(
       List(
-        Enumerator.Generator(Pat.Var(Term.Name("m")), Term.Name("decls")),
+        Enumerator.Generator(Pat.Var(tname("m")), tname("decls")),
         Enumerator.Guard(Term.ApplyInfix(
-          Term.ApplyInfix(
-            Term.Name("oneCond"),
-            Term.Name("&&"),
-            Type.ArgClause(Nil),
-            Term.ArgClause(List(Term.Name("cond")), None)
-          ),
-          Term.Name("&&"),
-          Type.ArgClause(Nil),
-          Term.ArgClause(List(Term.Name("satisfiable")), None)
+          Term.ApplyInfix(tname("oneCond"), tname("&&"), Nil, List(tname("cond"))),
+          tname("&&"),
+          Nil,
+          List(tname("satisfiable"))
         ))
       ),
-      Term.Block(Nil)
+      blk()
     )
     runTestAssert[Stat](code, layout)(tree)
   }