Repository: scalameta/scalameta (scala)

Issue:
Syntax function does not return the correct value for Ifs with an inner if without an else
Using:
  - Scalameta version 4.7.7
  - Scala 2.13.10

Steps to reproduce:
```scala
import scala.meta._

val expr1 = q"if (someCondition1) println(123)"
val expr2 = q"if (someCondition2) ($expr1) else println(321)"

println(expr2.syntax) // this is incorrect
```

actual:
```scala
if (someCondition2) if (someCondition1) println(123) else println(321)
```

expected:
```scala
if (someCondition2) (if (someCondition1) println(123)) else println(321)

OR

if (someCondition2) if (someCondition1) println(123) else () else println(321)
```

---

The `.syntax` is changing the semantics of the expression which shouldn't happen.

Pull request:
Fixes #3128

Patch:
diff --git a/scalameta/trees/shared/src/main/scala/scala/meta/internal/prettyprinters/TreeSyntax.scala b/scalameta/trees/shared/src/main/scala/scala/meta/internal/prettyprinters/TreeSyntax.scala
index 35c7aeb92d..4377fdfc19 100644
--- a/scalameta/trees/shared/src/main/scala/scala/meta/internal/prettyprinters/TreeSyntax.scala
+++ b/scalameta/trees/shared/src/main/scala/scala/meta/internal/prettyprinters/TreeSyntax.scala
@@ -86,7 +86,13 @@ object TreeSyntax {
     import SyntacticGroup.Type._, SyntacticGroup.Term._, SyntacticGroup.Pat._,
       SyntacticGroup.Literal, SyntacticGroup.Path
 
-    def p(og: SyntacticGroup, t: Tree, left: Boolean = false, right: Boolean = false) = {
+    def p(
+        og: SyntacticGroup,
+        t: Tree,
+        left: Boolean = false,
+        right: Boolean = false,
+        force: Boolean = false
+    ) = {
       def opNeedsParens(oo: String, io: String, customPrecedence: Boolean = true): Boolean = {
         def precedence(op: String) = if (customPrecedence) op.precedence else 0
         require(left != right)
@@ -111,7 +117,8 @@ object TreeSyntax {
         }
       }
       s(t) match {
-        case Show.Meta(ig: SyntacticGroup, res) if groupNeedsParens(og, ig) => s("(", res, ")")
+        case Show.Meta(ig: SyntacticGroup, res) if force || groupNeedsParens(og, ig) =>
+          s("(", res, ")")
         case res => res
       }
     }
@@ -411,6 +418,10 @@ object TreeSyntax {
           case _ => block(s(), t.stats)
         }
       case t: Term.If =>
+        val needParens: Boolean = t.thenp match {
+          case innerIf: Term.If => !guessHasElsep(innerIf) && guessHasElsep(t)
+          case _ => false
+        }
         m(
           Expr1,
           s(
@@ -419,7 +430,7 @@ object TreeSyntax {
             " (",
             t.cond,
             ") ",
-            p(Expr, t.thenp),
+            p(Expr, t.thenp, force = needParens),
             if (guessHasElsep(t)) s(" ", kw("else"), " ", p(Expr, t.elsep)) else s()
           )
         )


Test patch:
diff --git a/tests/shared/src/test/scala/scala/meta/tests/prettyprinters/SyntacticSuite.scala b/tests/shared/src/test/scala/scala/meta/tests/prettyprinters/SyntacticSuite.scala
index efbb1c6246..62f5c2ae1b 100644
--- a/tests/shared/src/test/scala/scala/meta/tests/prettyprinters/SyntacticSuite.scala
+++ b/tests/shared/src/test/scala/scala/meta/tests/prettyprinters/SyntacticSuite.scala
@@ -464,6 +464,8 @@ class SyntacticSuite extends scala.meta.tests.parsers.ParseSuite {
   test("some tricky parenthesization") {
     assertEquals(templStat("if (1) 2 else 3 + 4").syntax, "if (1) 2 else 3 + 4")
     assertEquals(templStat("(if (1) 2 else 3) + 4").syntax, "(if (1) 2 else 3) + 4")
+    assertEquals(templStat("if (1) (if (2) 3) else 4").syntax, "if (1) (if (2) 3) else 4")
+    assertEquals(templStat("if (1) if (2) 3 else () else 4").syntax, "if (1) (if (2) 3) else 4")
     assertEquals(
       templStat("if (1) 2 else 3 match { case _ => }").syntax,
       s"if (1) 2 else 3 match {${EOL}  case _ =>${EOL}}"