How to get a type of a case class from a reference type of its companion object #14154
-
Since it's not possible to get a type from a symbol, is there a way to get the case class type from the type of its companion object reference? import scala.quoted.*
trait CaseClass[Companion <: AnyRef]:
type CC <: Product
object CaseClass:
transparent inline given [Comp <: AnyRef]: CaseClass[Comp] = ${
macroImpl[Comp]
}
def macroImpl[Comp <: AnyRef](using
Quotes,
Type[Comp]
): Expr[CaseClass[Comp]] =
import quotes.reflect.*
val compObjTpe = TypeRepr.of[Comp]
val clsSym = compObjTpe.typeSymbol.companionClass
val clsType = ???
'{
new CaseClass[Comp]:
type CC = clsType.Underlying
}
end CaseClass |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
to do this, you can get the prefix of the type of the companion object, then use import scala.quoted.*
trait CaseClass[Companion <: AnyRef]:
type CC <: Product
object CaseClass:
type Aux[Companion <: AnyRef, Case <: Product] = CaseClass[Companion] { type CC = Case }
transparent inline given [Comp <: AnyRef]: CaseClass[Comp] = ${
macroImpl[Comp]
}
def macroImpl[Comp <: AnyRef](using
Quotes,
Type[Comp]
): Expr[CaseClass[Comp]] =
import quotes.reflect.*
val compObjTpe = TypeRepr.of[Comp]
val compPrefix = compObjTpe match
case TermRef(pre, _) => pre
case _ => report.throwError("Case class companion must be a term ref")
val clsSym = compObjTpe.typeSymbol.companionClass
if !clsSym.paramSymss.forall(_.headOption.forall(_.isTerm)) then
report.throwError("Case class with type parameters are not supported")
val clsTpe = compPrefix.select(clsSym)
clsTpe.asType match
case '[t & Product] =>
type Case = t & Product
'{ (new CaseClass[Comp] { type CC = Case }): CaseClass.Aux[Comp, Case] }
end CaseClass and here is test code: case class Foo(i: Int) derives CanEqual
@main def run =
val cc = summon[CaseClass[Foo.type]]
val mirror = summon[deriving.Mirror.ProductOf[cc.CC]]
assert(mirror.fromProduct(Tuple1(23)) == Foo(23)) This code will need more work probably for inner/local classes, and for classes with type parameters, but there is the bones here of something that could work |
Beta Was this translation helpful? Give feedback.
to do this, you can get the prefix of the type of the companion object, then use
select
on the prefix with the case class symbol, you need to explicitly refine the type of the anonymous class also to extract a usableCC
type from the returned value (I use aux pattern also, but unnecessary):