-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Summoned Mirror of Spliced Type is neither Sum nor Product #7974
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Thanks, but please try and reduce this to a short, single file, standalone example with no external dependencies of any sort. |
|
I am trying to do that as we speak 😄, but yes minimisations are important 🙈 |
@milessabin @biboudis Okay, here's as simple as I can make it. It has to be 2 files because otherwise the macro system complains that it can't define and execute a macro in the same file. Here's the buggy code: case class Person(name:String)
trait MyTypeclass[T] {
def useit(elem: T): String
}
object MyTypeclass {
inline def derived[T](implicit ev: Mirror.Of[T]): MyTypeclass[T] = new MyTypeclass[T] {
def useit(value: T): String =
inline ev match {
case m: Mirror.SumOf[T] => "it's a sum, yay!"
case m: Mirror.ProductOf[T] => "it's a product, yay!"
}
}
}
object Helper {
inline def findAndEncode[T](value: =>T): String = ${ findAndEncodeImpl('value) }
def findAndEncodeImpl[T](value: Expr[T])(given qctx: QuoteContext, t: Type[T]): Expr[String] = {
import qctx.tasty.{_, given}
val mirrorTpe = '[deriving.Mirror.Of[$t]]
val mirrorExpr = summonExpr(given mirrorTpe) match {
case Some(mirror) => mirror
}
'{
given MyTypeclass[T] = MyTypeclass.derived($mirrorExpr)
val mytc = summon[MyTypeclass[$t]]
mytc.useit($value)
}
}
} Here's how I run it: @main def run() = {
println(Helper.findAndEncode(Person("Joe")) )
} Code is also in git here: The following error happens:
Edit: |
While trying to minimize it further by eliminating derivation mechanism etc, we reached to the following that works. It made sense after moving the code of the quote inside the import scala.quoted._
import scala.deriving._
import scala.quoted.matching._
import scala.compiletime.{erasedValue, summonFrom}
trait TC[T] {
def foo(elem: T): Unit
}
object TC {
inline def derived[T](given ev: Mirror.Of[T]): TC[T] = new TC[T] {
def foo(elem: T): Unit =
inline ev match {
case m: Mirror.SumOf[T] => ???
case m: Mirror.ProductOf[T] => ???
}
}
}
object Helper {
inline def f[T](value: =>T): Unit = ${ macroImpl('value) }
def macroImpl[T](value: Expr[T])(given qctx: QuoteContext, t: Type[T]): Expr[Unit] = {
import qctx.tasty._
val mirrorTpe = '[Mirror.Of[$t]]
summonExpr(given mirrorTpe) match {
case Some('{$mirror: Mirror.SumOf[T]}) => '{
given TC[T] = TC.derived(given $mirror)
()
}
}
}
} WDYT? |
2nd version which doesn't mix import scala.quoted._
import scala.deriving._
import scala.quoted.matching._
import scala.compiletime.{erasedValue, summonFrom}
trait TC[T] {
def foo(elem: T): Unit
}
object TC {
// derived is a regular method now, merely a combinator lets say for Expr's (Expr => Expr)
def derived[T: Type](ev: Expr[Mirror.Of[T]])(given qctx: QuoteContext): Expr[TC[T]] = '{
new TC[T] {
def foo(elem: T): Unit = $ev
}
}
}
object Helper {
inline def f[T](value: =>T): Unit = ${ macroImpl('value) }
def macroImpl[T](value: Expr[T])(given qctx: QuoteContext, t: Type[T]): Expr[Unit] = {
import qctx.tasty._
val mirrorTpe = '[Mirror.Of[$t]]
val mirrorExpr = summonExpr(given mirrorTpe) match {
case Some(mirror) => mirror
}
// the precise type is done during macro expansion time
val preciseMirrorExpr = mirrorExpr match {
case '{$m: Mirror.SumOf[T]} => ???
case '{$m: Mirror.ProductOf[T]} => ???
}
val res = TC.derived[T](preciseMirrorExpr)
'{
given TC[T] = $res
()
}
}
} |
Wait a minute? So it’s impossible to summon an actual Mirror[T]? What if I need to get T’s fields? |
Compile (compilation of macro??) or runtime (expansion of macro)? |
The problem was clarified. PR #8011 adds the regression |
Uh oh!
There was an error while loading. Please reload this page.
A full demonstration of this issue is available here (there is nothing else in the repo):
https://github.com/deusaquilus/mirror_test
minimized code
Let's say that I summon a mirror for an encoder via summonExpr inside a macro like so:
Then I proceed to use it to summon a derived type-class (e.g. JsonEncoder) like so:
Then I try to declare a class and use the macro containing the above
summonExpr
:Instead of summoning a Product-Type mirror, it summons the following mirror:
Since this mirror does not contain any information about whether the type
T
is a product or sum type, it is impossible to use. A typical encoder will fail with the following error:expectation
A Product mirror for the type
PersonSimple
should be summoned that looks like this:Edit:
Note that it is interesting that with
summonFrom
this seems to work:Full example here:
https://github.com/deusaquilus/mirror_test/tree/summonFrom
What is the difference between what I am doing with
summonExpr
andsummonFrom
?The text was updated successfully, but these errors were encountered: