Closed
Description
Compiler version
3.2.0 (also 3.1.3)
Minimized code
Let's say we write a macro that takes apart a tuple into h *: t
and puts this into a specialized class HeadTail in order to make it easier to match.
trait HeadTail
object HeadTail:
case class Pair[H, T <: Tuple](h: H, t: T) extends HeadTail
object Nil extends HeadTail
object MatchHeadTail {
transparent inline def apply[A <: Tuple](inline tup: A): HeadTail = ${ applyImpl('tup) }
def applyImpl[A <: Tuple](tup: Expr[A])(using q: Quotes, tpe: Type[A]): Expr[HeadTail] = {
import quotes.reflect._
tpe match
case '[EmptyTuple] =>
'{ HeadTail.Nil }
case '[h *: t] =>
'{ HeadTail.Pair[h, t]($tup.productElement(0).asInstanceOf[h], $tup.drop(1).asInstanceOf[t]) }
}
}
Then we attempt to use it like so:
object HeadTailUse {
inline def concat[T <: Tuple](inline args: T): String =
inline MatchHeadTail(args) match
case HeadTail.Nil =>
""
case HeadTail.Pair(head, tail): HeadTail.Pair[h, t] =>
head.toString + concat(tail)
def main(args: Array[String]) = {
println(concat("Hello" *: 42 *: EmptyTuple))
}
}
An error will occur:
[error] -- Error: /home/alexi/git/tuple-example/src/main/scala/org/deusaquilus/HeadTailUse.scala:13:18
[error] 13 | println(concat("Hello" *: 42 *: EmptyTuple))
[error] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error] |cannot reduce inline match with
[error] | scrutinee: org.deusaquilus.HeadTail.Pair.apply[String, Int *: EmptyTuple.type](
[error] | {
[error] | val Tuple_this: EmptyTuple.type = EmptyTuple
[error] | {
[error] | val Tuple_this: (Int *: EmptyTuple.type) =
[error] | (
[error] | runtime.Tuples.cons(42, Tuple_this).asInstanceOf[
[error] | *:[Int, EmptyTuple.type]
[error] | ]
[error] | :*:[Int, EmptyTuple.type])
[error] | (
[error] | runtime.Tuples.cons("Hello", Tuple_this).asInstanceOf[
[error] | *:[String, Int *: EmptyTuple.type]
[error] | ]
[error] | :*:[String, Int *: EmptyTuple.type])
[error] | }
[error] | }.productElement(0).asInstanceOf[String]
...
[error] one error found
However if we just add a bogus binding e.g. bogusBinding @
then the whole thing will work:
inline def concat[T <: Tuple](inline args: T): String =
inline MatchHeadTail(args) match
case HeadTail.Nil =>
""
case bogusBinding @ HeadTail.Pair(head, tail): HeadTail.Pair[h, t] =>
head.toString + concat(tail)
// runMain org.deusaquilus.HeadTailUse
// Hello42
Expectation
The same thing should happen in both cases (i.e. the sample should work)
Repo
Code can be found here:
https://github.com/deusaquilus/headtail-macro-fail