Repository: scalameta/scalameta
Pull request #2675 (2022-03-12 23:17:43)

ScalametaParser: fix pattern infix type logic
It was duplicating code and inadvertently parsing the `op` after the `rhs`. Helps with #2315.



Patch:
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 1c6c0f0d9..508018084 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
@@ -827,11 +827,7 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) { parser =>
 
     @inline
     private def infixTypeRest(t: Type): Type =
-      infixTypeRestWithMode(t, InfixMode.FirstOp)
-
-    @inline
-    private def infixTypeRestWithMode(t: Type, mode: InfixMode.Value): Type =
-      infixTypeRestWithMode(t, mode, t.startTokenPos, identity)
+      infixTypeRestWithMode(t, InfixMode.FirstOp, t.startTokenPos, identity)
 
     @tailrec
     private final def infixTypeRestWithMode(
@@ -1028,11 +1024,10 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) { parser =>
       val t: Type = {
         if (allowInfix) {
           val t = if (token.is[LeftParen]) tupleInfixType() else compoundType()
-          def mkOp(t1: Type) = atPos(t, t1)(Type.ApplyInfix(t, typeName(), t1))
           token match {
             case KwForsome() => next(); copyPos(t)(Type.Existential(t, existentialStats()))
-            case Unquote() | Ident(_) if !isBar =>
-              infixTypeRestWithMode(mkOp(compoundType()), InfixMode.LeftOp)
+            case Ident("|") => t
+            case _: Unquote | _: Ident => infixTypeRest(t)
             case _ => t
           }
         } else {


Test patch:
diff --git a/tests/shared/src/test/scala/scala/meta/tests/parsers/ParseSuite.scala b/tests/shared/src/test/scala/scala/meta/tests/parsers/ParseSuite.scala
index bdcd4fd84..943b07ad4 100644
--- a/tests/shared/src/test/scala/scala/meta/tests/parsers/ParseSuite.scala
+++ b/tests/shared/src/test/scala/scala/meta/tests/parsers/ParseSuite.scala
@@ -25,6 +25,7 @@ class ParseSuite extends FunSuite with CommonTrees {
   def stat(code: String)(implicit dialect: Dialect) = code.applyRule(_.parseStat())
   def term(code: String)(implicit dialect: Dialect) = code.parseRule(_.expr())
   def pat(code: String)(implicit dialect: Dialect) = code.parseRule(_.pattern())
+  def patternTyp(code: String)(implicit dialect: Dialect) = code.parseRule(_.patternTyp())
   def tpe(code: String)(implicit dialect: Dialect) = code.parseRule(_.typ())
   def topStat(code: String)(implicit dialect: Dialect) =
     code.parseRule(p => p.statSeq(p.topStat).head)
diff --git a/tests/shared/src/test/scala/scala/meta/tests/parsers/PatSuite.scala b/tests/shared/src/test/scala/scala/meta/tests/parsers/PatSuite.scala
index b738840dc..aa820a5a8 100644
--- a/tests/shared/src/test/scala/scala/meta/tests/parsers/PatSuite.scala
+++ b/tests/shared/src/test/scala/scala/meta/tests/parsers/PatSuite.scala
@@ -5,6 +5,15 @@ import scala.meta._, Pat._
 import scala.meta.dialects.Scala211
 
 class PatSuite extends ParseSuite {
+
+  private def assertPat(expr: String)(tree: Tree): Unit = {
+    assertEquals(pat(expr).structure, tree.structure)
+  }
+
+  private def assertPatTyp(expr: String)(tree: Tree): Unit = {
+    assertEquals(patternTyp(expr).structure, tree.structure)
+  }
+
   test("_") {
     val Wildcard() = pat("_")
   }
@@ -45,6 +54,40 @@ class PatSuite extends ParseSuite {
     ) = pat("_: F[_]")
   }
 
+  test("t Map u") {
+    assertPatTyp("t Map u") {
+      Type.ApplyInfix(Type.Name("t"), Type.Name("Map"), Type.Name("u"))
+    }
+  }
+
+  test("patTyp: t & u | v") {
+    assertPatTyp("t & u | v") {
+      Type.ApplyInfix(
+        Type.ApplyInfix(Type.Name("t"), Type.Name("&"), Type.Name("u")),
+        Type.Name("|"),
+        Type.Name("v")
+      )
+    }
+  }
+
+  test("pat: F[t & u | v]()") {
+    assertPat("F[t & u | v]()") {
+      Pat.Extract(
+        Term.ApplyType(
+          Term.Name("F"),
+          List(
+            Type.ApplyInfix(
+              Type.ApplyInfix(Type.Name("t"), Type.Name("&"), Type.Name("u")),
+              Type.Name("|"),
+              Type.Name("v")
+            )
+          )
+        ),
+        Nil
+      )
+    }
+  }
+
   test("_: (t Map u)") {
     val Typed(Wildcard(), Type.ApplyInfix(Type.Name("t"), Type.Name("Map"), Type.Name("u"))) =
       pat("_: (t Map u)")