Home > Net >  Scala 3 macros: create a new polynmorphic function using the reflect api
Scala 3 macros: create a new polynmorphic function using the reflect api

Time:01-18

I intend to create the simple polymorphic function expression below using the Quotes.reflect API:

new PolyFunction {
  def apply[X](a: X): X = a
}

What I have attempted is shown below with parts that I could not implement replaced by ???:

val name: String = "$anon"
val parents = List(TypeTree.of[Object], TypeTree.of[PolyFunction])
def decls(cls: Symbol): List[Symbol] =
  List(
    Symbol.newMethod(
      cls,
      "apply",
      MethodType(List("a"))(
        { mt =>
          ???
        },
        mt => ???
      )
    )
  )
val cls = Symbol.newClass(Symbol.spliceOwner, name, parents = parents.map(_.tpe), decls, selfType = None)
val applySym = cls.declaredMethod("apply").head

val applyDef = DefDef(applySym, argss => Some(???))
val clsDef = ClassDef(cls, parents, body = List(applyDef))
val closure = Block(List(clsDef),Apply(Select(New(TypeIdent(cls)), cls.primaryConstructor), Nil))
closure.asExpr

The problem, mainly, is I am unable to declare the type parameter X, and its reference in the first value parameter and the functions return type. I have noticed some reflection functions are annotated as experimental.

CodePudding user response:

Try

import scala.annotation.experimental
import scala.quoted.*

inline def newPoly: PolyFunction = ${newPolyImpl}

@experimental
def newPolyImpl(using Quotes): Expr[PolyFunction] = {
  import quotes.reflect.*

  val name: String = "$anon"
  val parents = List(TypeTree.of[Object], TypeTree.of[PolyFunction])

  def decls(cls: Symbol): List[Symbol] =
    List(
      Symbol.newMethod(
        cls,
        "apply",
        PolyType(List("X"))(_ => List(TypeBounds.empty), polyType => {
          val typeParam = polyType.param(0)
          MethodType(List("a"))(_ => List(typeParam), _ => typeParam)
        })
      )
    )

  val cls = Symbol.newClass(Symbol.spliceOwner, name, parents = parents.map(_.tpe), decls, selfType = None)
  val applySym = cls.declaredMethod("apply").head

  // argss=List(List(TypeTree[TypeRef(NoPrefix,type X)]), List(Ident(a)))
  val applyDef = DefDef(applySym, argss => Some(argss(1)(0).asInstanceOf[Term]))
  val clsDef = ClassDef(cls, parents, body = List(applyDef))
  val closure = Block(List(clsDef), Apply(Select(New(TypeIdent(cls)), cls.primaryConstructor), Nil))
  closure.asExprOf[PolyFunction]
}

Usage:

newPoly

//scalac: {
//  class $anon extends java.lang.Object with scala.PolyFunction {
//    def apply[X](a: X): X = a
//  }
//  new $anon()
//}

Scala 3.2.1

Method Override with Scala 3 Macros

Scala3: Crafting Types Through Metaprogramming?

`tq` equivalent in Scala 3 macros

  • Related