I am writing a serialization library using Scala 3 macro programming. I want to generate the serializer dynamicly. Because this is a library, so I do not know what class to serializer during compile. So I need a runtime compile feature.
Code:
object CodecMacro {
import scala.quoted.staging.*
given Compiler = Compiler.make(getClass.getClassLoader)
// function 1: entry point: a Class object
def buildSerializer(clazz: Class[_]): Serializer = {
given staging.Compiler = staging.Compiler.make(getClass.getClassLoader)
val fn = (qctx: Quotes) ?=> {
given q: Quotes = qctx
buildSerializerAdapter(clazz)
}
staging.run(fn)
}
// function 2: convert clazz to generic T
// My main question is here
private def buildSerializerAdapter(clazz: Class[_])(using quotes: Quotes): Expr[Serializer] = {
import quotes.reflect.*
val tpe: TypeRepr = TypeRepr.typeConstructorOf(clazz)
val t = tpe.asType
type T = t.Underlying
buildSerializerImpl[T] // error: Missing type parameters for T
}
// function 3: Using a generic T to generate a Serializer
private def buildSerializerImpl[T: Type](using quotes: Quotes): Expr[Serializer] = {
val t = summon[Type[T]]
'{
type T = t.Underlying
new Serializer[T] {
override def serialize(writer: Writer, value: T): Unit = {
// Implemetation, not important
writer.writeString("aaa")
}
}
}
Function 1 is the entry point, which needs a Class object. Function 3 is the final implementation, which needs a generic type T.
Function 2 is to convert from Class object to generic type T and this is my main question.
My solution is
Class -> TypeRepr use: TypeRepr.typeConstructorOf(clazz)
TypeRepr -> Type use: TypeRepr.asType
Type -> type T use: Type.Underlying
I thought the type T under Type will solve my problem, but the compiler gives me an error: "Missing type parameters for T"
In Function 3: type T = t.Underlying
value: T
The generic type T is working fine.
Is there any way to convert Class object to generic type T?
Here is the way it should be done:
tpe.asType match
case '[t] =>
buildSerializerImpl[t]
This very strange invocation comes straight from the documentation of asType . It is necessary because asType
returns a Type[?]
where Type
accepts any type kind, but here we want a concrete type kind. The match would fail if the type was of higher kind, such as a Type[List]
(the List
constructor takes type arguments).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.