Repository: scalameta/scalameta (scala)

Issue:
Parsing fails in presence of significant space pattern match as a non-last parameter
scalameta 4.8.7 can't parse the following valid Scala code:

```scala
val component =
  List(1,2,3)
    .map: (props) =>
      TableOptions(
        getRowId = (row, _, _) =>
          row.value match
            case Left(HeaderRow(rowId, _)) => rowId
            case Right(stepRow)            => stepRow.step.rowId,
        onColumnSizingChange = dynTable.onColumnSizingChangeHandler
      )
```

It fails on line 3 with `; expected but => found`.

However, it works fine if the last parameter (`onColumnSizingChange`) is moved above `getRowId`, or if braces are added to the pattern match.

In other words, both of these work:
```scala
val component =
  List(1,2,3)
    .map: (props) =>
      TableOptions(
        onColumnSizingChange = dynTable.onColumnSizingChangeHandler,        
        getRowId = (row, _, _) =>
          row.value match
            case Left(HeaderRow(rowId, _)) => rowId
            case Right(stepRow)            => stepRow.step.rowId
      )
```

```scala
val component =
  List(1,2,3)
    .map: (props) =>
      TableOptions(
        getRowId = (row, _, _) =>
          row.value match {
            case Left(HeaderRow(rowId, _)) => rowId
            case Right(stepRow)            => stepRow.step.rowId
          },
        onColumnSizingChange = dynTable.onColumnSizingChangeHandler
      )
```


(Thanks @keynmol for helping isolate the issue).

Pull request:
`nextToken` ignored the `.next` field and tried to recompute the next token; instead, we should not do that if that field is already set.

Fixes #3664. Follow-up to #3542.

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 c3f7780253..7bbcd23dd5 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
@@ -21,9 +21,9 @@ private[parsers] class LazyTokenIterator private (
 
   import scannerTokens._
 
-  private def getNextTokenRef(): TokenRef = {
-    if (curr.next eq null) nextToken(curr) else curr.next
-  }
+  @inline
+  private def getNextTokenRef(): TokenRef =
+    nextToken(curr)
 
   override def next(): Unit = {
     prev = curr
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 ff1e5797b7..ae020322d4 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
@@ -325,15 +325,16 @@ final class ScannerTokens(val tokens: Tokens)(implicit dialect: Dialect) {
     }
   }
 
-  @inline
-  private[parsers] def nextToken(ref: TokenRef): TokenRef = {
-    val next = nextToken(ref.token, ref.pos, ref.nextPos, ref.regions)
-    ref.next = next
-    next
+  private[parsers] def nextToken(ref: TokenRef): TokenRef = ref.next match {
+    case null =>
+      val next = nextToken(ref.token, ref.pos, ref.nextPos, ref.regions)
+      ref.next = next
+      next
+    case nref => nref
   }
 
   @tailrec
-  private[parsers] def nextToken(
+  private def nextToken(
       prevToken: Token,
       prevPos: Int,
       currPos: Int,


Test patch:
diff --git a/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/SignificantIndentationSuite.scala b/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/SignificantIndentationSuite.scala
index 34ba09d6c0..80ed02935a 100644
--- a/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/SignificantIndentationSuite.scala
+++ b/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/SignificantIndentationSuite.scala
@@ -1675,6 +1675,36 @@ class SignificantIndentationSuite extends BaseDottySuite {
     runTestAssert[Stat](code, layout)(tree)
   }
 
+  test("#3542 apply with optional braces in intermediate arg, with multiple outdents") {
+    val code =
+      """|A(
+         |  foo = x =>
+         |    x match
+         |      case baz => baz,
+         |  bar = bar
+         |)
+         |""".stripMargin
+    val layout =
+      """|A(foo = x => x match {
+         |  case baz => baz
+         |}, bar = bar)
+         |""".stripMargin
+    val tree = Term.Apply(
+      tname("A"),
+      List(
+        Term.Assign(
+          tname("foo"),
+          Term.Function(
+            List(tparam("x")),
+            Term.Match(tname("x"), List(Case(Pat.Var(tname("baz")), None, tname("baz"))), Nil)
+          )
+        ),
+        Term.Assign(tname("bar"), tname("bar"))
+      )
+    )
+    runTestAssert[Stat](code, layout)(tree)
+  }
+
   test("indented-double-apply") {
     runTestAssert[Stat](
       """|def method =