Scala 3.6.4宏中如何调用inline方法?
问题场景
我在开发Scala 3.6.4序列化库时,定义了DiscriminatorCriteria类型类,用于为求和类型S的每个变体P生成对应的判别值。该类型类的核心方法discriminator被声明为:
inline:以支持scala.compiletime.erasedValue等编译期APItransparent:确保返回常量单例类型,让编译器能在编译期确定返回值的具体类型
在实现序列化/反序列化的派生宏时,我最初通过Expr.summon[DiscriminatorCriteria[S, P]]获取类型类实例,并在quote代码块中调用其discriminator方法,但编译时触发错误:
Deferred inline method discriminator in trait DiscriminatorCriteria cannot be invoked
我尝试了@DmytroMitin提出的summonDiscriminator封装方案,但仍然遇到相同的错误,最终通过直接使用Scala宏的底层Implicits.search方法解决了该问题。
问题原因
Expr.summon是Scala宏API中封装好的隐式实例获取方式,但对于包含inline方法的类型类,它无法正确解析方法的具体实现逻辑,导致编译器认为discriminator是一个未实现的延迟方法(deferred inline method),从而拒绝调用。
解决方案
直接使用宏反射层的Implicits.search方法来获取类型类实例,它能直接获取到隐式实例的语法树节点,让编译器正确识别并内联展开inline方法。
代码示例
首先定义一个底层的隐式实例获取工具:
import scala.quoted.* def summonDiscriminator[S: Type, P: Type](using Quotes): Expr[DiscriminatorCriteria[S, P]] = { import quotes.reflect.* Implicits.search(TypeRepr.of[DiscriminatorCriteria[S, P]]) match { case success: ImplicitSearchSuccess => success.tree.asExprOf[DiscriminatorCriteria[S, P]] case failure: ImplicitSearchFailure => report.errorAndAbort(failure.explanation) } }
然后在派生宏中调用该工具并使用discriminator方法:
def deriveSerializer[S: Type](using Quotes): Expr[Serializer[S]] = { '{ new Serializer[S] { override def serialize(value: S): String = { // 针对求和类型的每个变体P获取判别值 ${ // 省略变体遍历逻辑,仅展示核心调用方式 val discriminatorExpr = summonDiscriminator[S, P].map(dc => '{ $dc.discriminator }) discriminatorExpr.getOrElse(report.errorAndAbort("No DiscriminatorCriteria instance found")) } // 后续序列化逻辑 } } } }
说明
通过Implicits.search获取的隐式实例语法树,能够让编译器正确处理inline方法的内联展开,同时保留transparent方法带来的常量单例类型推导能力,完美适配序列化库中对编译期常量判别值的需求。
内容的提问来源于stack exchange,提问作者Readren

