So this works:
trait Foo[A]
object Foo:
given [A <: Product](using m: Mirror.ProductOf[A]): Foo[A] = ???
def foo =
summon[Foo[(String, Int)]]
However, when the trait is made contra- (or co-) variant:
trait Bar[-A]
object Bar:
given [A <: Product](using m: Mirror.ProductOf[A]): Bar[A] = ???
def bar =
summon[Bar[(String, Int)]]
it fails with Failed to synthesize an instance of type deriving.Mirror.ProductOf[A]: trait Product is not a generic product because it is not a case class.
on the last line.
First, the error message doesn’t make sense to me at all. I’m also not able to wrap my head around whether the variance should matter here.
Any chance this could be a compiler bug?
1 Like
kavedaa
October 15, 2022, 10:43am
2
For the record: the issue that caused this is fixed in 3.2.1-RC1.
opened 04:29AM - 25 Jul 21 UTC
closed 08:39PM - 04 Aug 22 UTC
itype:bug
area:typer
area:typeclass-derivation
## Compiler version
3.0.1
## Minimized code
```Scala
import scala.deri… ving.*
import scala.compiletime.{erasedValue, summonInline}
inline def summonAll[T <: Tuple]: List[Eq[_]] =
inline erasedValue[T] match
case _: EmptyTuple => Nil
case _: (t *: ts) => summonInline[Eq[t]] :: summonAll[ts]
trait Eq[-T]:
def eqv(x: T, y: T): Boolean
object Eq:
given Eq[Int] with
def eqv(x: Int, y: Int) = x == y
def check(elem: Eq[_])(x: Any, y: Any): Boolean =
elem.asInstanceOf[Eq[Any]].eqv(x, y)
def iterator[T](p: T) = p.asInstanceOf[Product].productIterator
def eqSum[T](s: Mirror.SumOf[T], elems: => List[Eq[_]]): Eq[T] =
new Eq[T]:
def eqv(x: T, y: T): Boolean =
val ordx = s.ordinal(x)
(s.ordinal(y) == ordx) && check(elems(ordx))(x, y)
def eqProduct[T](p: Mirror.ProductOf[T], elems: => List[Eq[_]]): Eq[T] =
new Eq[T]:
def eqv(x: T, y: T): Boolean =
iterator(x).zip(iterator(y)).zip(elems.iterator).forall {
case ((x, y), elem) => check(elem)(x, y)
}
inline given derived[T](using m: Mirror.Of[T]): Eq[T] =
lazy val elemInstances = summonAll[m.MirroredElemTypes]
inline m match
case s: Mirror.SumOf[T] => eqSum(s, elemInstances)
case p: Mirror.ProductOf[T] => eqProduct(p, elemInstances)
end Eq
enum Opt[+T] derives Eq:
case Sm(t: T)
case Nn
@main def test(): Unit =
import Opt.*
val eqoi = summon[Eq[Opt[Int]]]
assert(eqoi.eqv(Sm(23), Sm(23)))
assert(!eqoi.eqv(Sm(23), Sm(13)))
assert(!eqoi.eqv(Sm(23), Nn))
```
## Output
```scala
no implicit argument of type deriving.Mirror.Of[T] was found for parameter m of given instance derived in object Eq
where: T is a type variable with constraint >: Opt[T]
```
## Expectation
This example from the documentation does not work when `Eq` is contravariant instead of invariant.
3 Likes