Repository: scalameta/scalameta (scala)

Issue:
Unsupported SIP-64 syntax
It looks like https://github.com/scalameta/scalameta/pull/4068 didn't fix all SIP-64 cases

```
➜  ~ cat Test.scala
//> using dep org.scalameta::scalameta:4.12.2

import scala.meta._

object Main {
  def main(args: Array[String]): Unit = {
    val src = Input.String("""given List[Int] => Object {}""")
    val p = implicitly[parsers.Parse[Stat]]
    println(p.apply(src, dialects.Scala3).get.structure)
  }
}
```

```
➜  ~ scala Test.scala
Exception in thread "main" <input>:1: error: abstract givens cannot be anonymous
given List[Int] => Object {}
      ^
	at scala.meta.internal.parsers.Reporter.syntaxError(Reporter.scala:16)
	at scala.meta.internal.parsers.Reporter.syntaxError$(Reporter.scala:9)
	at scala.meta.internal.parsers.Reporter$$anon$1.syntaxError(Reporter.scala:22)
	at scala.meta.internal.parsers.Reporter.syntaxError(Reporter.scala:18)
	at scala.meta.internal.parsers.Reporter.syntaxError$(Reporter.scala:9)
	at scala.meta.internal.parsers.Reporter$$anon$1.syntaxError(Reporter.scala:22)
	at scala.meta.internal.parsers.ScalametaParser.givenDecl$$anonfun$1(ScalametaParser.scala:3536)
	at scala.meta.internal.parsers.ScalametaParser.autoEndPos(ScalametaParser.scala:388)
	at scala.meta.internal.parsers.ScalametaParser.autoEndPos(ScalametaParser.scala:393)
	at scala.meta.internal.parsers.ScalametaParser.givenDecl(ScalametaParser.scala:3539)
	at scala.meta.internal.parsers.ScalametaParser.defOrDclOrSecondaryCtor(ScalametaParser.scala:3421)
	at scala.meta.internal.parsers.ScalametaParser.nonLocalDefOrDcl(ScalametaParser.scala:3404)
	at scala.meta.internal.parsers.ScalametaParser$$anon$1.applyOrElse(ScalametaParser.scala:4264)
	at scala.meta.internal.parsers.ScalametaParser$$anon$1.applyOrElse(ScalametaParser.scala:4259)
	at scala.meta.internal.parsers.ScalametaParser.entrypointStat(ScalametaParser.scala:4289)
	at scala.meta.internal.parsers.ScalametaParser.parseStat$$anonfun$1(ScalametaParser.scala:70)
	at scala.meta.internal.parsers.ScalametaParser.parseRuleAfterBOF(ScalametaParser.scala:60)
	at scala.meta.internal.parsers.ScalametaParser.parseRule(ScalametaParser.scala:55)
	at scala.meta.internal.parsers.ScalametaParser.parseStat(ScalametaParser.scala:70)
	at scala.meta.parsers.Parse$.parseStat$lzyINIT1$$anonfun$1(Parse.scala:15)
	at scala.meta.parsers.Parse$$anon$1.apply(Parse.scala:37)
	at Main$.main(Test.scala:9)
	at Main.main(Test.scala)
```

Pull request:
Fixes #4091.

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 170d5ee855..080ba0cf68 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
@@ -3557,10 +3557,10 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
         if (!tryAheadNot[Indentation.Indent]) None
         else if (newSyntax) givenSigAfterColon(name)
         else Some(GivenSig(name))
-      else if (tryAhead[LeftBracket]) givenSigOnBracket(name) // only with old syntax
+      else if (tryAhead[LeftBracket]) givenSigOnBracket(name)
       else if (tryAhead[LeftParen]) givenSigOnParen(name) // only with old syntax
       else if (tryAhead[EOL])
-        if (tryAhead[LeftBracket]) givenSigOnBracket(name) // only with old syntax
+        if (tryAhead[LeftBracket]) givenSigOnBracket(name)
         else if (tryAhead[LeftParen]) givenSigOnParen(name) // only with old syntax
         else None
       else if (newSyntax)
@@ -3589,7 +3589,10 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
     else if (!name.isAnonymous) {
       val typeName = copyPos(name)(Type.Name(name.value))
       val tpe = convertNameTypeParamClauseToType(typeName, pcg.tparamClause)
-      Some(GivenSig(anonNameAt(name), declType = Some(tpe)))
+      val anon = anonNameAt(name)
+      if (dialect.allowImprovedTypeClassesSyntax && acceptOpt[RightArrow])
+        givenSigAfterArrow(anon, convertTypeToTermParamClause(tpe))
+      else Some(GivenSig(anon, declType = Some(tpe)))
     } else if (dialect.allowImprovedTypeClassesSyntax && acceptOpt[RightArrow])
       givenSigAfterArrow(name, pcg.tparamClause)
     else None
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 e88b74b2d1..088402b34f 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
@@ -895,22 +895,25 @@ object TreeSyntax {
         val derived = r(t.derives, "derives ", ", ", "")
         val ptype = t.parent match {
           case Some(p: Defn.Given) =>
-            val isNew = givenSigUsesNewSyntax(p.paramClauseGroups)(!t.body.origin.tokensOpt.forall {
-              _.rfindWideNot(_.is[Token.Trivia], -1).is[Token.KwWith] // still old syntax
-            })
+            val isNew = givenSigUsesNewSyntax(p.paramClauseGroups) {
+              t.inits.forall(_.argClauses.isEmpty) && !t.body.origin.tokensOpt.forall {
+                _.rfindWideNot(_.is[Token.Trivia], -1).is[Token.KwWith] // still old syntax
+              }
+            }
             if (isNew) Decl.Given else Defn.Given
           case Some(_: Term.NewAnonymous) => Term.NewAnonymous
           case _ => null
         }
-        def isGiven = ptype eq Defn.Given
+        def isOldGiven = ptype eq Defn.Given
+        def isNewGiven = ptype eq Decl.Given
         val pbody = s(t.body)
         val body =
           if (pbody.isEmpty) t.inits match {
-            case x :: Nil if isGiven => o("with {}", x.argClauses.isEmpty)
+            case x :: Nil if isOldGiven => o("with {}", x.argClauses.isEmpty)
             case _ :: xs if xs.nonEmpty => s()
-            case _ => o("{}", (ptype eq Term.NewAnonymous) && pearly.isEmpty)
+            case _ => o("{}", (ptype eq Term.NewAnonymous) && pearly.isEmpty || isNewGiven)
           }
-          else w("with ", pbody, isGiven)
+          else w("with ", pbody, isOldGiven)
         val noExtends = ptype != null || pparents.isEmpty && pearly.isEmpty
         r(" ")(o("extends", !noExtends), pearly, pparents, derived, body)
       case t: Template.Body =>


Test patch:
diff --git a/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/GivenSyntax36Suite.scala b/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/GivenSyntax36Suite.scala
index 6c9e536d61..fe10c77ad8 100644
--- a/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/GivenSyntax36Suite.scala
+++ b/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/GivenSyntax36Suite.scala
@@ -960,4 +960,17 @@ class GivenSyntax36Suite extends BaseDottySuite {
     runTestAssert[Stat](code, layout)(tree)
   }
 
+  test("#4091 given") {
+    val code = "given List[Int] => Object {}"
+    val layout = "given (List[Int]) => Object {}"
+    val tree = Defn.Given(
+      Nil,
+      anon,
+      Nil,
+      List(List(tparam("", papply("List", "Int")))),
+      tpl(List(init("Object")), Nil)
+    )
+    runTestAssert[Stat](code, layout)(tree)
+  }
+
 }