scala / scala3

The Scala 3 compiler, also known as Dotty.
https://dotty.epfl.ch
Apache License 2.0
5.86k stars 1.06k forks source link

Errors when using a defined parameterized unapply #13125

Open hamdiallam opened 3 years ago

hamdiallam commented 3 years ago

Compiler version: 3.01

When defining an unapply for a class that has a parameterized type extending a covariant type, the compiler errors or emits warning when pattern matching on the type.

The only way this works is to make the subtype covariant and matching on the type directly, supplying the generic type.

However, the unapply for a case class works fine. No issues in Scala 2

Example

sealed trait Bar[+A]

case class Foo[A](a: A) extends Bar[A]

class Baz[A](val a: A) extends Bar[A]
object Baz {
  def unapply[A](baz: Baz[A]): Some[A] = Some(baz.a)
}

Case 1

def func[A](b: Bar[A]): A = {
    b match {
      case Foo(a) => a
      case Baz(a) => a // ERROR: Found:  (a : A$2), Required: A
    }
}

Case 2

def func[A](b: Bar[A]): A = {
    b match {
      case Foo(a) => a
      case Baz(a: A) => a // Warning: the type test for A cannot be checked at runtime
    }
}

This works.

class Baz[+A](a: A) extends Bar[A] // Must define `Baz` as covariant
def func[A](b: Bar[A]): A = {
    b match {
      case Foo(a) => a
      case b: Baz[A] => b.a
    }
}
smarter commented 3 years ago
def unapply[A](a : A): Some[A] = Some(a)

That looks wrong to me, this unapply takes a value of type A and returns a value of type A, did you mean something like:

  def unapply[A](a : Baz[A]): Some[A] = ...
hamdiallam commented 3 years ago

Yes, my bad. That was a typo on my end. Updated the description

smarter commented 3 years ago
   case Baz(a) => a // ERROR: Found:  (a : A$2), Required: A

At this point we should know that A$2 <: A so that does look like a bug.