Repository: scalameta/scalameta (scala)

Issue:
After_X_Y_Z stubs prevent round-tripping in quasiquotes
Probably known, but I didn't see an issue for it. Pinning it here for others searching.

During the ABI-preserving migration, forward-compatible `unapply` methods have been into inner objects named `After_X_Y_Z`. Since the quasiquotes are unaware that they should use these new unapply methods, the following blows up:

```scala
scala> val x = q"""new Foo(a = a, b = b)"""
x: meta.Term.New = new Foo(a = a, b = b)

scala> val q"""new Foo(a = a, b = b)""" = x

scala> val q"""new Foo(..$params)""" = x
<console>:16: error: exception during macro expansion:
java.lang.UnsupportedOperationException: unsupported unquoting position
        at scala.meta.Term$ArgClause$Quasi$TermArgClauseQuasiImpl.values(Trees.scala:113)
        at scala.meta.Term$ArgClause$Quasi$TermArgClauseQuasiImpl.values(Trees.scala:113)
        at scala.meta.internal.trees.PlaceholderChecks$.$anonfun$hasPlaceholder$2(PlaceholderChecks.scala:41)
        at scala.meta.internal.trees.PlaceholderChecks$.$anonfun$hasPlaceholder$2$adapted(PlaceholderChecks.scala:41)
            ....
        at scala.meta.internal.quasiquotes.ReificationMacros.unapply(ReificationMacros.scala:55)
            ....
        at scala.tools.nsc.typechecker.Macros.macroExpandWithRuntime(Macros.scala:849)

       val q"""new Foo(..$params)""" = x
           ^
```

Rolling back to scalameta 4.5.13 shows the expected behavior:

```
@ val q"""new Foo(..${params})""" = x
params: List[Term] = List(Term.Assign(Term.Name("a"), Term.Name("a")), Term.Assign(Term.Name("b"), Term.Name("b")))
```

Pull request:
Fixes #3388.

Patch:
diff --git a/scalameta/trees/shared/src/main/scala/scala/meta/internal/trees/PlaceholderChecks.scala b/scalameta/trees/shared/src/main/scala/scala/meta/internal/trees/PlaceholderChecks.scala
index fc5fa2f148..d4bd7af731 100644
--- a/scalameta/trees/shared/src/main/scala/scala/meta/internal/trees/PlaceholderChecks.scala
+++ b/scalameta/trees/shared/src/main/scala/scala/meta/internal/trees/PlaceholderChecks.scala
@@ -38,7 +38,8 @@ object PlaceholderChecks {
         case t: Term.Select => queue += t.qual; iter
         case t: Term.Tuple => t.args.exists(isPlaceholder) || queue.nonEmpty && iter
         case t: Init =>
-          t.argClauses.exists(_.values.exists(isPlaceholder)) || queue.nonEmpty && iter
+          t.argClauses.exists(x => !x.isInstanceOf[Quasi] && x.values.exists(isPlaceholder)) ||
+          queue.nonEmpty && iter
         case t: Term.Apply => queue += t.fun; queue += t.argClause; iter
         case t: Term.ArgClause =>
           isBlockPlaceholder(t.values) || (t.parent match {


Test patch:
diff --git a/tests/shared/src/test/scala/scala/meta/tests/quasiquotes/SuccessSuite.scala b/tests/shared/src/test/scala/scala/meta/tests/quasiquotes/SuccessSuite.scala
index f0744c4706..ad6261ce3c 100644
--- a/tests/shared/src/test/scala/scala/meta/tests/quasiquotes/SuccessSuite.scala
+++ b/tests/shared/src/test/scala/scala/meta/tests/quasiquotes/SuccessSuite.scala
@@ -2988,4 +2988,16 @@ class SuccessSuite extends TreeSuiteBase {
     }
   }
 
+  test("#3388") {
+    val term = q"""new Foo(a = a, b = b)"""
+    val assignA = Term.Assign(Term.Name("a"), Term.Name("a"))
+    val assignB = Term.Assign(Term.Name("b"), Term.Name("b"))
+
+    val q"""new Foo(..$params2)""" = term
+    assertTrees(params2: _*)(assignA, assignB)
+
+    val q"""new Foo(...$params3)""" = term
+    assertTrees(params3: _*)(Term.ArgClause(List(assignA, assignB), None))
+  }
+
 }