Description
Compiler version
3.0, 3.1, 3.2, 3.3
Problem
import scala.quoted.*
def test(using Quotes) = '{ def f[T](x: T) = ${ identity('{ val y: T = x; y }) } }
Compiling with -Xprint:splicing
, we can see the variables defined in the outer quote and used in the inner one (T, x
). In that phase we replace the splice with a quote hole {{{ 0 | T | T, x | ... }
.
[[syntax trees at end of splicing]] // t/Test.scala
package <empty> {
import scala.quoted.*
final lazy module val Test$package: Test$package = new Test$package()
@SourceFile("t/Test.scala") final module class Test$package() extends Object() { this: Test$package.type =>
private def writeReplace(): AnyRef = new scala.runtime.ModuleSerializationProxy(classOf[Test$package.type])
def test(using x$1: quoted.Quotes): quoted.Expr[Unit] =
'{
{
def f[T >: Nothing <: Any](x: T): T =
{{{ 0 | T | T, x | ... /* a lambda with the contents of the splice */ }}}
()
}
}.apply(x$1)
}
}
We currently pickle this hole we have to pickle the captured variables T, x
as trees.
https://github.com/lampepfl/dotty/blob/d36cd2d142f490e5ba7fcb29906b6b0a27cf8702/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala#L668-L673
The problem is that we do not know if the tree has to be unpickled as a type or a term. We unpickle all of them as terms
https://github.com/lampepfl/dotty/blob/d36cd2d142f490e5ba7fcb29906b6b0a27cf8702/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala#L1470-L1476
If a type contains a term reference, such as a TypeTree(tp: TermRef)
, the unpicker will unpickle it as an Ident
or Select
. This implies that the type is unpickled as a term, which causes trouble later when we wrap them in quoted.{Expr,Type}
.
Solution 1
We have to pickle the hole with a format where we can unpickle types a types and terms as terms. For this we need to split the arguments into type and term arguments. We need to make sure that the order of arguments retains the order that is defined in the splicing phase. Therefore, we need to split the type arguments from term arguments during the splicing phase.
The tricky part is to find a way to encode this tree in tasty without braking TASTy binary compatibility.
Solution 2
Define a method and a type in the standard library to encode the holes.
This would make the pickled tasty slightly larger.