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

"unreachable code" false-positives, "match not exhaustive" false-negative warnings when matching on HKTs #11620

Open
ryan-williams opened this issue Jul 8, 2019 · 6 comments

Comments

Projects
None yet
4 participants
@ryan-williams
Copy link

commented Jul 8, 2019

scalafiddle; repros on 2.12.8 and 2.13.0

sealed trait A[+T]
 case class A1[+T](t : T       ) extends A[T]
 case class A2[+T](t1: T, t2: T) extends A[T]

sealed trait B[+T] {
  type AA[+U] <: A[U]
  def a: AA[T]
}
object B {
  type Aux[+_A[+_], +T] = B[T] { type AA[+U] <: _A[U] }
  object Aux {
    def unapply[_A[+U] <: A[U], T](b: Aux[_A, T]): Option[_A[T]] = Some(b.a)
  }
  
  def apply[_A[+U] <: A[U], T](_a: _A[T]): Aux[_A, T] =
    new B[T] { type AA[+U] = _A[U] ; val a: _A[T] = _a }
    
  def unapply[T](b: B[T]): Option[b.AA[T]] = Some(b.a)
}

def foo[T](b: B[T]) = b match {
  case B(A1(t))  t
  case B(A2(t, _))  t
}

def foo2[_A[+U] <: A[U], T](b: B.Aux[_A, T]) = b match {
  case B.Aux(a @ A1(_   ))  a.t
  case B.Aux(a @ A2(_, _))  a.t1  // 👎 (false-positive): unreachable code
}

def foo3[_A[+U] <: A[U], T](b: B.Aux[_A, T]) = b match {
  case B.Aux(a: A1[T])  a.t
  case B.Aux(a: A2[T])  a.t1  // 👎 (false-positive): unreachable code
}

def foo4[T](b: B[T]) = b match {
  case B(A1(t))  t  // 👎 (false-negative): incomplete match
}

val b1: B.Aux[A1, Int] = B(A1(111))
val b2: B.Aux[A2, Int] = B(A2(222, 333))

println(s"${foo (b1)} ${foo (b2)}")
println(s"${foo2(b1)} ${foo2(b2)}")
println(s"${foo3(b1)} ${foo3(b2)}")

Compilation generates false-positive warnings as annotated above:

[warn]       case B.Aux(a @ A2(_, _)) ⇒ a.t1  // 👎 (false-positive): unreachable code
[warn]                                    ^
[warn]       case B.Aux(a: A2[T]) ⇒ a.t1  // 👎 (false-positive): unreachable code
[warn]                                ^

(scalafiddle doesn't display these for some reason)

All three printlns work as expected, reaching the "unreachable code":

111 222
111 222
111 222

The compiler also fails to flag the inexhaustive match in foo4.

@ryan-williams ryan-williams changed the title "unreachable code" false positives, "match not exhaustive" false-negative warnings when matching on HKTs "unreachable code" false-positives, "match not exhaustive" false-negative warnings when matching on HKTs Jul 8, 2019

@joroKr21

This comment has been minimized.

Copy link

commented Jul 18, 2019

About foo4, I think exhaustiveness is not checked when using custom unapply methods 🤔

@smarter

This comment has been minimized.

Copy link

commented Jul 18, 2019

I think exhaustiveness is not checked when using custom unapply methods thinking

You can mark a custom unapply as irrefutable by making its result type Some[...] instead of Option[...]:

  def unapply[T](b: B[T]): Some[b.AA[T]] = Some(b.a)
@joroKr21

This comment has been minimized.

Copy link

commented Jul 18, 2019

This doesn't seem to work in Scala 2. Still doesn't warn:

  object A {
    def unapply(x: Int): Some[Int] = Some(x)
  }

  42 match {
    case A(5) => 5
  }
@smarter

This comment has been minimized.

Copy link

commented Jul 18, 2019

It helps in cases like this:

scala> object A { def unapply(x: Int): Some[Int] = Some(x) }
defined object A

scala> object B { def unapply(x: Int): Option[Int] = Some(x) }
defined object B

scala> List(1) match { case A(x) :: xs => }
<console>:13: warning: match may not be exhaustive.
It would fail on the following input: Nil
       List(1) match { case A(x) :: xs => }
           ^

scala> List(1) match { case B(x) :: xs => }
@joroKr21

This comment has been minimized.

Copy link

commented Jul 18, 2019

Ah so it works if the custom unapply is a leaf but not when it's a branch in the pattern match.
Well that's confusing 😕

@joroKr21

This comment has been minimized.

Copy link

commented Jul 19, 2019

Related? #11457

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.