Repository: scalameta/scalameta
Pull request #3126 (2023-05-22 18:03:22)

LazyTokenIterator: further simplify undoIndent()
Follow-up to #3123 fixing #3113.


Patch:
diff --git a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/LazyTokenIterator.scala b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/LazyTokenIterator.scala
index 5c421cb24..7e0c316a5 100644
--- a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/LazyTokenIterator.scala
+++ b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/LazyTokenIterator.scala
@@ -60,17 +60,9 @@ private[parsers] class LazyTokenIterator private (
    */
   def undoIndent(): Unit = {
     curr.regions match {
-      case (region: SepRegionIndented) :: others if curr.token.is[Indentation.Indent] =>
-        val ref = getNextTokenRef()
-        resetCurr(ref.withRegions(ref.regions match {
-          // deal with  region added by `case` in enum after self type
-          case RegionArrow :: _ => others
-          // if no region was added
-          case `region` :: _ => others
-          // keep any added region in `next()`
-          case head :: _ => head :: others
-          case xs => xs
-        }))
+      case (_: SepRegionIndented) :: others if curr.token.is[Indentation.Indent] =>
+        val ref = nextToken(curr.token, curr.pos, curr.nextPos, others)
+        resetCurr(ref)
       case _ =>
     }
   }
diff --git a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScalametaParser.scala b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScalametaParser.scala
index c2ac790e6..270febc87 100644
--- a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScalametaParser.scala
+++ b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScalametaParser.scala
@@ -3099,7 +3099,12 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) { parser =>
         mods += autoEndPos(prevTokenPos)(Mod.Inline())
       }
     }
-    val hasExplicitMods = mods.view.drop(numAnnots).exists(!_.is[Mod.Quasi])
+    val hasExplicitMods = mods.view.drop(numAnnots).exists {
+      case _: Mod.Quasi => false
+      case m: Mod.Private => m.within.is[Name.Anonymous]
+      case m: Mod.Protected => m.within.is[Name.Anonymous]
+      case _ => true
+    }
 
     mod.foreach { mod =>
       val clazz = mod.getClass
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 604cf618a..6757c98c1 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
@@ -617,8 +617,7 @@ final class ScannerTokens(val tokens: Tokens)(implicit dialect: Dialect) {
             // !next.is[RightBrace] - braces can sometimes have -1 and we can start indent on }
             prev match {
               case _ if nextIndent < 0 || next.is[RightBrace] => None
-              case _ if prevToken.is[Indentation.Indent] => None
-              case _ if prevToken.is[Indentation.Outdent] => None
+              case _ if prevToken.is[Indentation] => None
               // if does not work with indentation in pattern matches
               case _: KwIf if sepRegions.headOption.contains(RegionArrow) => None
               case _: KwCatch | _: KwMatch =>
diff --git a/scalameta/tokens/shared/src/main/scala/scala/meta/tokens/Token.scala b/scalameta/tokens/shared/src/main/scala/scala/meta/tokens/Token.scala
index 3883ac0dd..8989a791c 100644
--- a/scalameta/tokens/shared/src/main/scala/scala/meta/tokens/Token.scala
+++ b/scalameta/tokens/shared/src/main/scala/scala/meta/tokens/Token.scala
@@ -150,9 +150,10 @@ object Token {
     @freeform("xml end") class End extends Token
   }
 
+  @branch trait Indentation extends Whitespace
   object Indentation {
-    @freeform("indent") class Indent extends Token
-    @freeform("outdent") class Outdent extends Token
+    @freeform("indent") class Indent extends Indentation
+    @freeform("outdent") class Outdent extends Indentation
   }
 
   // Trivia
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 35c7aeb92..4377fdfc1 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/jvm/src/test/scala-2.13/scala/meta/tests/api/SurfaceSuite.scala b/tests/jvm/src/test/scala-2.13/scala/meta/tests/api/SurfaceSuite.scala
index f5b0664ab..824dbd445 100644
--- a/tests/jvm/src/test/scala-2.13/scala/meta/tests/api/SurfaceSuite.scala
+++ b/tests/jvm/src/test/scala-2.13/scala/meta/tests/api/SurfaceSuite.scala
@@ -163,7 +163,6 @@ class SurfaceSuite extends FunSuite {
       |scala.meta.tokenizers.Tokenized.Success *
       |scala.meta.tokens
       |scala.meta.tokens.Token
-      |scala.meta.tokens.Token.Indentation *
       |scala.meta.tokens.Token.Interpolation *
       |scala.meta.tokens.Token.Xml *
       |scala.meta.tokens.Tokens
diff --git a/tests/shared/src/test/scala/scala/meta/tests/parsers/ModSuite.scala b/tests/shared/src/test/scala/scala/meta/tests/parsers/ModSuite.scala
index 3b9b532ae..82b7f7077 100644
--- a/tests/shared/src/test/scala/scala/meta/tests/parsers/ModSuite.scala
+++ b/tests/shared/src/test/scala/scala/meta/tests/parsers/ModSuite.scala
@@ -838,4 +838,28 @@ class ModSuite extends ParseSuite {
     assert(actual.contains(expected), actual)
   }
 
+  test("#3122 missing val after package-private modifier") {
+    val code = "case class Foo(private[example] field: String)"
+    val expected =
+      Defn.Class(
+        List(Mod.Case()),
+        Type.Name("Foo"),
+        Nil,
+        Ctor.Primary(
+          Nil,
+          Name(""),
+          List(
+            Term.Param(
+              List(Mod.Private(Name("example"))),
+              Term.Name("field"),
+              Some(Type.Name("String")),
+              None
+            ) :: Nil
+          )
+        ),
+        Template(Nil, Nil, Self(Name(""), None), Nil, Nil)
+      )
+    assertTree(templStat(code))(expected)
+  }
+
 }
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 efbb1c624..62f5c2ae1 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}}"