This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Pattern matching is not exhaustive in Function when it's implicitly converted to PartialFunction

4 replies
Alexander Nemish
Joined: 2011-05-24,
User offline. Last seen 42 years 45 weeks ago.

Hi,

When I use implicit conversion from PartialFunction to Function,
pattern matching becomes non-exhaustive in the following code.
Is this a bug?

object Bug {
sealed abstract class T
case object A extends T
case object B extends T

implicit def t2p(t: T => Unit) = new PartialFunction[T, Unit] {
def apply(v1: T) {t.apply(v1)}
def isDefinedAt(x: T): Boolean = true
}

def f(t: PartialFunction[T, Unit]) = t.apply(B)

// compiles without any warnings
f((t: T) => t match {
case A => ()
})

// warning: match is not exhaustive!
f(t2p((t: T) => t match {
case A => ()
}))
}

Cheers,
Alexander Nemish

Som Snytt
Joined: 2011-09-19,
User offline. Last seen 42 years 45 weeks ago.
Re: Pattern matching is not exhaustive in Function when it's im
FWIW, I would expect this behavior: when the literal is a PartialFunction, you don't get the warning.  When you explicitly call t2p, the type of the literal is Function and you get the warning.

Analogous to:
 val p: PartialFunction[T,Unit] = { case A => () }
 val q: Function[T,Unit] = { case A => () }

In your first case, there is no warning and the implicit is not used; f takes a PF and the compiler supplies it from the literal.  That's the same as calling f(p).


On Fri, Dec 23, 2011 at 8:11 AM, Alexander Nemish <anemish@googlemail.com> wrote:
Hi,

When I use implicit conversion from PartialFunction to Function,
pattern matching becomes non-exhaustive in the following code.
Is this a bug?

object Bug {
 sealed abstract class T
 case object A extends T
 case object B extends T

 implicit def t2p(t: T => Unit) = new PartialFunction[T, Unit] {
   def apply(v1: T) {t.apply(v1)}
   def isDefinedAt(x: T): Boolean = true
 }

 def f(t: PartialFunction[T, Unit]) = t.apply(B)

 // compiles without any warnings
 f((t: T) => t match {
   case A => ()
 })

 // warning: match is not exhaustive!
 f(t2p((t: T) => t match {
   case A => ()
 }))
}

Cheers,
Alexander Nemish

Alexander Nemish
Joined: 2011-05-24,
User offline. Last seen 42 years 45 weeks ago.
Re: Pattern matching is not exhaustive in Function when it's im
Thank you, Som.
My bad, I actually have a bit more complex situation:
object Bug { sealed abstract class T case object A extends T case object B extends T
 case class E(t: T)
 implicit def t2p(t: T => Unit) = new PartialFunction[E, Unit] {   def apply(v1: E) {t.apply(v1.t)}   def isDefinedAt(x: E): Boolean = true  }
 def f(t: PartialFunction[E, Unit]) = error("Dosn't matter")
 // compiles without any warnings f((t: T) => t match {   case A => ()  })
 // warning: match is not exhaustive! f(t2p((t: T) => t match {   case A => () }))}
In this case, if you comment the implicit conversion function, it won't compile, so it does use the conversion but still no warning. Is that a bug? 
2011/12/23 Som Snytt <som.snytt@gmail.com>
FWIW, I would expect this behavior: when the literal is a PartialFunction, you don't get the warning.  When you explicitly call t2p, the type of the literal is Function and you get the warning.

Analogous to:
 val p: PartialFunction[T,Unit] = { case A => () }
 val q: Function[T,Unit] = { case A => () }

In your first case, there is no warning and the implicit is not used; f takes a PF and the compiler supplies it from the literal.  That's the same as calling f(p).


On Fri, Dec 23, 2011 at 8:11 AM, Alexander Nemish <anemish@googlemail.com> wrote:
Hi,

When I use implicit conversion from PartialFunction to Function,
pattern matching becomes non-exhaustive in the following code.
Is this a bug?

object Bug {
 sealed abstract class T
 case object A extends T
 case object B extends T

 implicit def t2p(t: T => Unit) = new PartialFunction[T, Unit] {
   def apply(v1: T) {t.apply(v1)}
   def isDefinedAt(x: T): Boolean = true
 }

 def f(t: PartialFunction[T, Unit]) = t.apply(B)

 // compiles without any warnings
 f((t: T) => t match {
   case A => ()
 })

 // warning: match is not exhaustive!
 f(t2p((t: T) => t match {
   case A => ()
 }))
}

Cheers,
Alexander Nemish


E. Labun
Joined: 2010-06-20,
User offline. Last seen 42 years 45 weeks ago.
Re: Pattern matching is not exhaustive in Function when it's im

I believe that in both cases the inferred type of the expression ´(t: T) => t match {case A => ()}´
is ´PartialFunction[T, Unit]´.

And in both cases, in order to be a parameter of the method t2p, it gets widened to the
´Function1[T, Unit]´. Should it always trigger an exhaustiveness check?

However in the case of the explicit ´t2p´ call an exaustiveness check is performed, and in the case
of the implicitly inserted call not.

Seems to be an inconsistency to me, but may be I'm wrong somewhere.

Som Snytt
Joined: 2011-09-19,
User offline. Last seen 42 years 45 weeks ago.
Re: Pattern matching is not exhaustive in Function when it's im
The implicit t2p sees a PF in the implicit case (hence no warning) and a Function1 in the explicit case (hence the warning).

I think the general rule is that you get a complete function unless you annotate otherwise.  Some discussion is at section 15.7
http://www.artima.com/pins1ed/case-classes-and-pattern-matching.html
and a lack of discussion in the spec section 8.5.

In the example, you get a PF because f expects to receive one. (And you wouldn't get a PF when calling g(s: String) and converting to a String.)

You can tell it what you want and get warnings back:
f(((t: T) => t match { case A => () }): Function1[T,Unit])

Is it intuitive to infer the PF for the function literal in the face of conversions to arbitrary PFs?  Maybe, if this is just composition.  Also, as to the least surprise principle, the implicit knows to handle PFs because it produces one; conversely, the caller knows the signature of f, but might be vaguely unaware of the implicit.

On Fri, Dec 23, 2011 at 2:25 PM, Alexander Nemish <anemish@googlemail.com> wrote:
Thank you, Som.
My bad, I actually have a bit more complex situation:
object Bug { sealed abstract class T case object A extends T  case object B extends T
 case class E(t: T)
 implicit def t2p(t: T => Unit) = new PartialFunction[E, Unit] {   def apply(v1: E) {t.apply(v1.t)}   def isDefinedAt(x: E): Boolean = true  }
 def f(t: PartialFunction[E, Unit]) = error("Dosn't matter")
 // compiles without any warnings f((t: T) => t match {    case A => ()  })
 // warning: match is not exhaustive! f(t2p((t: T) => t match {   case A => () }))}
In this case, if you comment the implicit conversion function, it won't compile, so it does use the conversion but still no warning. Is that a bug? 
2011/12/23 Som Snytt <som.snytt@gmail.com>
FWIW, I would expect this behavior: when the literal is a PartialFunction, you don't get the warning.  When you explicitly call t2p, the type of the literal is Function and you get the warning.

Analogous to:
 val p: PartialFunction[T,Unit] = { case A => () }
 val q: Function[T,Unit] = { case A => () }

In your first case, there is no warning and the implicit is not used; f takes a PF and the compiler supplies it from the literal.  That's the same as calling f(p).


On Fri, Dec 23, 2011 at 8:11 AM, Alexander Nemish <anemish@googlemail.com> wrote:
Hi,

When I use implicit conversion from PartialFunction to Function,
pattern matching becomes non-exhaustive in the following code.
Is this a bug?

object Bug {
 sealed abstract class T
 case object A extends T
 case object B extends T

 implicit def t2p(t: T => Unit) = new PartialFunction[T, Unit] {
   def apply(v1: T) {t.apply(v1)}
   def isDefinedAt(x: T): Boolean = true
 }

 def f(t: PartialFunction[T, Unit]) = t.apply(B)

 // compiles without any warnings
 f((t: T) => t match {
   case A => ()
 })

 // warning: match is not exhaustive!
 f(t2p((t: T) => t match {
   case A => ()
 }))
}

Cheers,
Alexander Nemish



Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland