Skip to content

Avoid bridge clashes involving value classes for anonymous classes #11264

Open
@smarter

Description

@smarter

The following compiles with Scala 2 but not with Scala 3:

trait Monad[F[_]] {
  def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B]
}

final case class Dual[A](getDual: A) extends AnyVal

object Dual {
  implicit val dualInstances: Monad[Dual] = new Monad[Dual] {
    def flatMap[A,B](fa: Dual[A])(f: A => Dual[B]): Dual[B] = f(fa.getDual) // error in Scala 3, OK in Scala 2
  }
}

The error we get is:

bridge generated for member method flatMap[A, B](fa: Dual[A])(f: A => Dual[B]): Dual[B] in anonymous class Object with Monad {...}
which overrides method flatMap[A, B](fa: F[A])(f: A => F[B]): F[B] in trait Monad
clashes with definition of the member itself; both have erased type (fa: Object, f: Function1): Object.

This is a known fundamental problem with value classes: we need two flatMap methods depending on whether we're in a context where we know we're dealing with Dual[A] (and thus can erase it to its underlying type) or in a generic context (and thus need to keep Dual[A] boxed), but the generic type parameter erases to Object and the unboxed representation of this value class is also Object, so we end up with two methods with the same signature. In fact, Scala 2 will emit the same error if we make the subclass non-anonymous:

object Dual {
  class MonadDual extends Monad[Dual] {
    def flatMap[A,B](fa: Dual[A])(f: A => Dual[B]): Dual[B] = f(fa.getDual)
  }
  implicit val dualInstances: Monad[Dual] = new MonadDual // error in Scala 2 and 3
}

So how come the first example works in Scala 2? Turns out there's a special-case just for anonymous classes, where the non-generic method gets renamed because it cannot be called anyway: scala/scala#3428. We could do the same to make cross-compilation easier, this can be done post-3.0 since it doesn't change anything for code that currently compiles.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions