Skip to content
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

Since 0.16.0-RC3, value classes can't be derived #7000

Open
kfish610 opened this issue Aug 6, 2019 · 5 comments
Open

Since 0.16.0-RC3, value classes can't be derived #7000

kfish610 opened this issue Aug 6, 2019 · 5 comments

Comments

@kfish610
Copy link

kfish610 commented Aug 6, 2019

minimized code

import scala.deriving._
import compiletime._
case class B(v: Double) extends AnyVal
val m = summon[Mirror.ProductOf[B]]

expectation

m should be a mirror, instead it throws the error no implicit argument of type deriving.Mirror.ProductOf[B] was found for parameter x of method the in object DottyPredef

@milessabin
Copy link
Contributor

milessabin commented Aug 7, 2019

A restriction excluding Mirrors for value classes was introduced in 5c924ca (see whyNotGenericProduct in SymUtils.scala. Dropping this restriction allows the example above to compile and run as expected.

However, if the value class is made polymorphic, ie.

case class C[T](v: T) extends AnyVal
val m1 = the[Mirror.ProductOf[C[Double]]]

it fails during erasure,

-- Error: tests/run/i7000.scala:13:13 ------------------------------------------
13 |  case class C[T](v: T) extends AnyVal
   |             ^
   |bridge generated for member method fromProduct(x$0: Product): Test.C.MirroredMonoType in object C
   |which overrides method fromProduct(p: Product): Product.this.MirroredMonoType in trait Product
   |clashes with definition of the member itself; both have erased type (x$0: Product): Object."

attempting to bridge between,

method fromProduct (x$0: Product): ErasedValueType(Test.C, Object)

and

method fromProduct (p: Product): Object

The second of which, I think, is the erased form of,

sealed trait Mirror {
  type MirroredMonoType
}
trait Product extends Mirror {
  def fromProduct(p: scala.Product): MirroredMonoType
}

The immediate explanation for compiler to refusing to construct the bridge is that ErasedValueType(Test.C, Object) doesn't match Object. What's less clear to me is why that's the case.

I could do with some pointers from someone more familiar with the interaction of polymorphic value types and erasure than me /cc @smarter @odersky.

@smarter
Copy link
Member

smarter commented Aug 7, 2019

It's complicated, see #1905 for the background, if you make sure that the value class underlying type is something other than Object (e.g., case class C[T <: Foo](v: T) extends AnyVal to erase it to Foo), then it should avoid these weird clashes.

@milessabin
Copy link
Contributor

@smarter #1905 looks gnarly :-(

Adding a bound to ensure that the result type of fromProduct doesn't erase to Object seems to do the trick for these examples.

I could relax the condition in whyNotGenericProduct to match, ie. we generate mirrors for value classes iff the result type of fromProduct doesn't erase to Object. That probably covers most of the cases that people care about. WDYT?

@smarter
Copy link
Member

smarter commented Aug 8, 2019

I could relax the condition in whyNotGenericProduct to match, ie. we generate mirrors for value classes iff the result type of fromProduct doesn't erase to Object. That probably covers most of the cases that people care about. WDYT?

Sounds good to me.

I wonder if you could change the definition of MirroredMonoType to type MirroredMonoType <: Product, this way def fromProduct(...): MirroredMonoType would erase to def fromProduct(...): Product which should reduce the chance of getting a clash.

@milessabin
Copy link
Contributor

I wonder if you could change the definition of MirroredMonoType to type MirroredMonoType <: Product

We can't do that in general, but it might be possible to special-case value classes in that way. I'll give it a try.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants