-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Bridge method clash with value class #8001
Comments
There's a long history about this bug which is really a shortcoming of the value class encoding. Given that value classes are not pursued further, and the bug would likely cost a person several weeks to fix, I am not sure we will ever fix it. I do hope there is a workaround. |
@odersky We can easily work around this, thanks. |
@travisbrown Good to know, thanks! |
minimise to this case class Box(a: Any) extends AnyVal or perhaps this to avoid class Box(a: Any) extends AnyVal
object Box extends (Any => Box)
def apply(a: Any): Box = new Box(a) |
@bishabosha The code that Travis posted compiles fine in Scala 2, while yours will error in Scala 2 as well. I think the bug (or just difference from scala 2, don't know...) here is that dotc thinks that |
Yes, exactly. I'm working on a fix. |
The Dotty build currently fails with errors like this: ``` [error] -- Error: /home/travis/build/[secure]/refined/modules/core/shared/src/main/scala-3.0+/eu/timepit/refined/api/RefType.scala:85:19 [error] 85 | override def unsafeWrap[T, P](t: T): Refined[T, P] = [error] | ^ [error] |bridge generated for member method unsafeWrap[T, P](t: T): eu.timepit.refined.api.Refined[T, P] in anonymous class Object with eu.timepit.refined.api.RefType {...} [error] |which overrides method unsafeWrap[T, P](t: T): F[T, P] in trait RefType [error] |clashes with definition of the member itself; both have erased type (t: Object): Object." ``` This is a known limitation of value classes, see scala/scala3#8001. `Refined` as opaque type sidesteps this issue.
* Make Refined an opaque type on Dotty The Dotty build currently fails with errors like this: ``` [error] -- Error: /home/travis/build/[secure]/refined/modules/core/shared/src/main/scala-3.0+/eu/timepit/refined/api/RefType.scala:85:19 [error] 85 | override def unsafeWrap[T, P](t: T): Refined[T, P] = [error] | ^ [error] |bridge generated for member method unsafeWrap[T, P](t: T): eu.timepit.refined.api.Refined[T, P] in anonymous class Object with eu.timepit.refined.api.RefType {...} [error] |which overrides method unsafeWrap[T, P](t: T): F[T, P] in trait RefType [error] |clashes with definition of the member itself; both have erased type (t: Object): Object." ``` This is a known limitation of value classes, see scala/scala3#8001. `Refined` as opaque type sidesteps this issue. * We don't need to call value inside the companion
Previously given: class Poly[A](val value: A) extends AnyVal We always erased `Poly[X]` to `Object`, no matter the value `X`, because the erasure was the erased underlying type as seen from its definition, and not as seen from the current prefix. But it turns out that in Scala 2, `Foo[Int]` will be erased to `Integer` instead (it would have made more sense to use `int` but I suspect this is more accidental than designed). To be binary-compatible with Scala 2 and to support the same kind of overloads we need to replicate its behavior, more precisely the rules I was able to reverse-engineer are: - Given `class Foo[A](x: A) extends AnyVal`, `Foo[X]` should erase like `X`, except if its a primitive in which case it erases to the boxed version of this primitive. - Given `class Bar[A](x: Array[A]) extends AnyVal`, `Bar[X]` will be erased like `Array[A]` as seen from its definition site, no matter the `X` (same if `A` is bounded). I was able to adapt our implementation of value class erasure to these new rules without too much refactoring through one compromise: a value class can no longer wrap another value class. This was never supported by Scala 2 so we can afford to not support it either.
Previously given: class Poly[A](val value: A) extends AnyVal We always erased `Poly[X]` to `Object`, no matter the value `X`, because the erasure was the erased underlying type as seen from its definition, and not as seen from the current prefix. But it turns out that in Scala 2, `Foo[Int]` will be erased to `Integer` instead (it would have made more sense to use `int` but I suspect this is more accidental than designed). To be binary-compatible with Scala 2 and to support the same kind of overloads we need to replicate its behavior, more precisely the rules I was able to reverse-engineer are: - Given `class Foo[A](x: A) extends AnyVal`, `Foo[X]` should erase like `X`, except if its a primitive in which case it erases to the boxed version of this primitive. - Given `class Bar[A](x: Array[A]) extends AnyVal`, `Bar[X]` will be erased like `Array[A]` as seen from its definition site, no matter the `X` (same if `A` is bounded). I was able to adapt our implementation of value class erasure to these new rules without too much refactoring through one compromise: a value class can no longer wrap another value class. This was never supported by Scala 2 so we can afford to not support it either.
Fix #8001: Erase polymorphic value classes like Scala 2
This is marked as fixed in M3, but there's another situation where this happens: https://scastie.scala-lang.org/g5dE8K7wT5aCPYTYFETtLA
Compiler:
|
Hmm, interesting, if I replace the anonymous instantiation by: object Foo extends Monad[Dual] {
def flatMap[A,B](fa: Dual[A])(f: A => Dual[B]): Dual[B] = f(fa.getDual)
} Then Scala 2 emits the same error as Dotty. It looks like Scala 2 has some extra magic to deal with the special-case of value class bridge clashes in anonymous classes where it can get away with renaming one of the method to avoid the clash: scala/scala#3428, feel free to open an issue about this, but I don't know if we have the bandwidth to port this in time for 3.0. |
I have to admit I don't understand at all what's going on, and what a possible workaround could be. Having said that, I found this problem while minimizing another problem found by @fmsbeekmans while porting semigroups to Dotty. A similar instantiation produced the following message:
... and I haven't yet minimized it in a satisfactory way, nor can I tell whether or not this is an internal error. The error goes away when removing |
That |
minimized code
Compilation output
expectation
Another minimization from the Cats tests. Scala 2 is fine with this.
The text was updated successfully, but these errors were encountered: