union-derivation icon indicating copy to clipboard operation
union-derivation copied to clipboard

Potential issue with deriving type classes that are already based on Mirrors

Open matwojcik opened this issue 1 year ago • 2 comments

Hi,

I have a typeclass which is generated using Mirrors. There is a compilation failure returned when I use UnionDerivation on top of it.

Take a look at this minimal example:

//> using scala "3.5.2"
//> using lib "io.github.irevive::union-derivation-core:0.2.1"
//> using options "-Yretain-trees"

import scala.annotation.nowarn
import scala.deriving.Mirror

import io.github.irevive.union.derivation.IsUnion
import io.github.irevive.union.derivation.UnionDerivation

trait Show[A] {
  def show(value: A): String
}

object Show {
  inline given derivedUnion[A](using IsUnion[A]): Show[A] = UnionDerivation.derive[Show, A]

  @nowarn("msg=New anonymous class definition will be duplicated at each inline site")
  inline given instance[A](using m: Mirror.ProductOf[A]): Show[A] = {
    println(s"$m") // if you remove it, then it compiles
    new Show[A] {
      def show(value: A): String = value.toString()
    }
  }
}

case class A(x: String)
case class B(y: Int)

// it also compiles when you uncomment those:
// given Show[A] = Show.instance[A]
// given Show[B] = Show.instance[B]

@main def hello() = println(Show.derivedUnion[A | B].show(A("1")))

It returns

Error: Error while emitting example.scala
val m$proxy1

The error goes away if you either don't use the mirror (even if you declare it in using clause) or if you generate the instances outside of UnionDerivation macro.

matwojcik avatar Dec 20 '24 13:12 matwojcik

This change made the snippet compile:

- inline given instance[A](using m: Mirror.ProductOf[A]): Show[A] = {
+ inline given instance[A](using inline m: Mirror.ProductOf[A]): Show[A] = {

It may be a non-trivial compiler issue, but I didn't dive into it, to be honest.

iRevive avatar Dec 31 '24 20:12 iRevive

Since 3.3.0 it is going to fail https://github.com/scala/scala3/issues/16804 when you use anything from this inlined param (like m.MirroredElemLabels) - see this for context.

(m : scala.deriving.Mirror.ProductOf[A]) is not a valid type prefix, since it is not an immutable path
[error]    |Inline parameters are not considered immutable paths and cannot be used as
[error]    |singleton types.
[error]    |
[error]    |Hint: Removing the `inline` qualifier from the `m` parameter
[error]    |may help resolve this issue.

I can see that they witnessed issues with it in circe - https://github.com/circe/circe/pull/2287 / https://github.com/circe/circe/pull/2278

matwojcik avatar Jan 02 '25 08:01 matwojcik