In a Macros.scala file we have
import scala.quoted._
object Macros {
object HList {
sealed trait HList
case class HCons[+HD, TL <: HList](hd: HD, tl: TL) extends HList
case object HNil extends HList
private def sizeImpl(e: Expr[HList], n:Int)(using qctx:QuoteContext): Expr[Int] = {
import qctx.tasty._
e match {
case '{HCons(_,$t)} =>
//case '{HCons($a,$t)} =>
//case '{HCons(($a,$b),$t)} =>
sizeImpl(t,n+1)
case '{HNil} => Expr(n)
}
}
inline def size(inline expr: HList ): Int = {
${sizeImpl('expr,0)}
}
}
}
In a Main.scala file we have
object Main {
def main(args: Array[String]): Unit = {
import HList._
val hl0n = size( HCons(("1",1), HCons(("2",2), HCons(("3",3),HNil))) )
println(s"size(?) = $hl0n")
}
}
[error] -- Error: /IdeaProjects/snol/tutorial/src/ad/Main.scala:130:19 --------
[error] 130 | val hl0n = size( HCons(("1",2), HCons(("2",2), HCons(("3",3),HNil))) )
[error] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error] | Exception occurred while executing macro expansion.
[error] | scala.MatchError: '{ ... } (of class scala.internal.quoted.Expr)
[error] |
[error] | This location contains code that was inlined from Main.scala:130
[error] one error found
I expected a correct match. If we use:
case '{HCons($a,$t)} =>
or
case '{HCons(($a,$b),$t)} =>
matching works correctly.
Tested on 0.26.0-RC1
Awkwardly the behavior is correct. The pattern case '{HCons(_,$t)} will never match because _ is never a valid term.
The correct way to write this wildcard pattern is
case '{HCons($_,$t)} =>
// or
case '{HCons(${_},$t)} =>
where _ is a pattern equivalent to a in $a where we do not name the a.
We should reject the _ in pattern '{HCons(_,$t)} as it is neve useful. We can also suggest the user to write $_ instead.
Actually case '{HCons(_,$t)} is equivalent to case '{x => HCons(x,$t)}. Therefore it could match such a lambda. We can warn and expect the users to write the explicit lambda or the $_ instead.
@nicolasstucki : Great diagnosis 馃憤 It's easy to have the wrong intuition when working with quoted patterns.
Most helpful comment
Actually
case '{HCons(_,$t)}is equivalent tocase '{x => HCons(x,$t)}. Therefore it could match such a lambda. We can warn and expect the users to write the explicit lambda or the$_instead.