Scala 3.6.4:如何在引用表达式中调用带类型边界的多态方法
解决Scala 3宏中调用类型类方法时的子类型约束问题
问题原因
你遇到的报错是因为宏上下文里,编译器无法自动推导headType是A的子类型——尽管我们知道Sum类型的MirroredElemTypes中的每个元素必然是A的子类型,但宏的类型检查器不会自动识别这个隐含关系,必须显式提供证据。
解决方案
可以通过两种方式解决:
方法1:显式提供子类型证据
利用Type的<:<关系,在调用getFor时带上隐式的子类型证据,让编译器认可headType <: A:
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] => val discriminatorCriteriaExpr = Expr.summon[DiscriminatorCriteria[A]].get // 显式获取headType <:< A的证据 val subTypeEvidence = Expr.summon[headType <:< A].get // 调用时带上证据,让编译器确认子类型约束 val discriminator: Expr[Int] = '{ given _: headType <:< A = $subTypeEvidence $discriminatorCriteriaExpr.getFor[headType] } // 补充后续返回Expr[Serializer[A]]的逻辑,示例占位 '{ Serializer.make($discriminator) } } case _ => // 处理非Sum类型的情况 ??? } }
方法2:直接强制类型转换(简洁但需谨慎)
如果确定headType必然是A的子类型,可以直接用Type.asInstanceOf强制转换类型参数,绕过编译器检查:
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] => val discriminatorCriteriaExpr = Expr.summon[DiscriminatorCriteria[A]].get // 强制将headType转换为A的子类型 val headTypeAsSubtype = Type.of[headType].asInstanceOf[Type { type T <: A }] val discriminator: Expr[Int] = '{ $discriminatorCriteriaExpr.getFor[${Type.show[headTypeAsSubtype.T]}] } '{ Serializer.make($discriminator) } } case _ => ??? } }
补充说明
第一种方法更安全,通过隐式证据让编译器验证子类型关系;第二种方法更简洁,但依赖你对Sum类型结构的确定性,适合能保证headType一定是A子类型的场景。
内容的提问来源于stack exchange,提问作者Readren
相关产品推荐
相关产品推荐

