scalamacrosmetaprogrammingscala-macrosscala-3

In scala 3.6.4, how to call a polymorphic method with type bounds from inside a quoted expression?


The method to call is the SAM of the following type class:

trait DiscriminatorCriteria[A] {
    def getFor[V <: A]: Int
}

And the headType to pass as type argument (to type parameter V) was obtained from a Mirror.SumOf.MirroredElemTypes using a type quote pattern matching like this:

def deriveSerializerImpl[A: Type](using quotes: Quotes): Expr[Serializer[A]] = {
    import quotes.reflect.*
    Expr.summon[Mirror.Of[A]] match {
        case Some('{ $m: Mirror.SumOf[A] {type MirroredElemTypes = elemTypes} }) =>
            Type.of[elemTypes] match {
                case '[headType *: tailTypes] =>
                    ...
}

I need to define a quoted expression that calls getFor like this:

case '[headType *: tailTypes] =>
    val discriminatorCriteriaExpr = Expr.summon[DiscriminatorCriteria[A]].get  // asume that exists
    val discriminator: Expr[Int] = '{ $discriminatorCriteriaExpr.getFor[headType] }

But the compiler complains saying that headType does not conform to the upper bound A.


Solution

  • Try

    val discriminator: Expr[Int] = '{ $discriminatorCriteriaExpr.getFor[headType & A] }
    
    case Some('{ $m: Mirror.SumOf[A] {type MirroredElemTypes = elemTypes} }) =>
      '{ tag[elemTypes] } match {
        case '{
          type headType <: A
          tag[`headType` *: tailTypes]
        } =>
    

    where dummy method is defined

    def tag[A] = ???
    
    type ABounded[T <: A] = T
    
    val discriminator: Expr[Int] = '{ $discriminatorCriteriaExpr.getFor[ABounded[headType]] }
    
    Type.of[elemTypes] match {
      case '[type headType <: A; `headType` *: tailTypes] => 
    
    Type.of[elemTypes] match {
      case '[
        type headType <: A
        `headType` *: tailTypes
      ] => 
    

    Explicit type conversion in Scala 3 macros

    What Scala 3 syntax can match on a Type and its Type parameters in the context of a macro?

    Replacement for `x.asType match { case '[type t <: S; t] => ...` in Scala 3.3 (LTS)