Skip to content

Summoned Mirror of Spliced Type is neither Sum nor Product #7974

Closed
@deusaquilus

Description

@deusaquilus

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:

    val mirrorTpe = '[Mirror.Of[$t]]
    val mirrorExpr = summonExpr(given mirrorTpe) match {
      case Some(mirror) => mirror
    }

Then I proceed to use it to summon a derived type-class (e.g. JsonEncoder) like so:

    '{
      given JsonEncoder[T] = JsonEncoder.derived($mirrorExpr)
      val encoder = summon[JsonEncoder[$t]]
      encoder.encode($value)
    }

Then I try to declare a class and use the macro containing the above summonExpr:

case class PersonSimple(name:String, age:Int)
val stuff = PersonSimple("Joe", 123)
println(SummonJsonEncoderTest.encodeAndMessAroundType(stuff) )

Instead of summoning a Product-Type mirror, it summons the following mirror:

scala.deriving.Mirror{
  MirroredType = t.$splice; MirroredMonoType = t.$splice; 
    MirroredElemTypes <: Tuple
}

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:

[error] -- Error: /home/alexander/git/dotty/mirror_test/src/main/scala/org/deusaquilus/SummonJsonEncoderTest.scala:22:48 
[error] 22 |      given JsonEncoder[T] = JsonEncoder.derived($mirrorExpr)
[error]    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error]    |            cannot reduce inline match with
[error]    |             scrutinee:  {
[error]    |              ev
[error]    |            } : (ev : 
[error]    |              scala.deriving.Mirror{
[error]    |                MirroredType = t.$splice; MirroredMonoType = t.$splice; 
[error]    |                  MirroredElemTypes <: Tuple
[error]    |              }
[error]    |            )
[error]    |             patterns :  case m @ _:deriving.Mirror.SumOf[T]
[error]    |                         case m @ _:deriving.Mirror.ProductOf[T]
[error]    | This location contains code that was inlined from JsonEncoder.scala:28

expectation

A Product mirror for the type PersonSimple should be summoned that looks like this:

  (
    scala.deriving.Mirror{
      MirroredType = PersonSimple; MirroredMonoType = PersonSimple; 
        MirroredElemTypes <: Tuple
    }
   & 
    scala.deriving.Mirror.Product{
      MirroredMonoType = PersonSimple; MirroredType = PersonSimple; 
        MirroredLabel = "PersonSimple"
    }
  ){MirroredElemTypes = (String, Int); MirroredElemLabels = ("name", "age")}

Edit:

Note that it is interesting that with summonFrom this seems to work:

inline def encodeAndMessAroundType[T](value: =>T): String = {
    summonFrom {
      case m: Mirror.ProductOf[T] => derived(m).encode(value)
    }
  }

Full example here:
https://github.com/deusaquilus/mirror_test/tree/summonFrom

What is the difference between what I am doing with summonExpr and summonFrom?

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions