-
Notifications
You must be signed in to change notification settings - Fork 21
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
pattern matching over covariant GADT unsound #8563
Comments
Imported From: https://issues.scala-lang.org/browse/SI-8563?orig=1 |
@retronym said: object Test {
sealed trait Node[+A]
// case class L[C,D](f: C => D) extends Node[C => D]
class L[C, D](val f: C => D) extends Node[C => D]
object L {
def unapply[C, D](x$0: Test.L[C,D]): Option[C => D] = ???
}
def test[A,B](n: Node[A => B]): A => B = n match {
case l: L[c,d] => l.f
}
def main(args: Array[String]) {
println {
test(new L[Int,Int](identity) with Node[Nothing]: Node[Int => String])(3): String
}
}
} |
@retronym said: |
Owen Healy (ellbur) said: object Test4 extends App {
sealed trait Node[+A] {
def extract[R](taker: A => R): R
}
class L[C,D](f: C => D) extends Node[C => D] {
def extract[R](taker: (C => D) => R) = taker(f)
}
def test[A,B](n: Node[A => B]): A => B = n.extract(f => f)
println {
test(new L[Int,Int](identity) with Node[Nothing]: Node[Int => String])(3): String
}
} But, this produces a compile error for the lack of an appropriate |
@Blaisorblade said: On the original example hereAll examples in #7714 are unrelated, other than by "GADT type refinement in patterns is broken". The first example here has exactly the same unsoundness I found (described not only in the paper, but also mentioned in my comment to SI-6944) — the type refinement inside test is not valid, because The original author of the pattern matcher (Burak Emir) wrote papers on the topic, but the languages he describes always forbid |
@Blaisorblade said (edited on May 5, 2014 8:07:15 PM UTC): On Jason Zaugg's variantI'm slightly confused on the need for an extractor. On Scala 2.10.3 and 2.11.0, you don't need any extractor to reproduce the bug — a typed match does not use it. (The use of a typed extractor is a slight difference with the example I mentioned before in #6944, but it appears immaterial). To wit: object Test {
sealed trait Node[+A]
// case class L[C,D](f: C => D) extends Node[C => D]
class L[C, D](val f: C => D) extends Node[C => D]
def test[A,B](n: Node[A => B]): A => B = n match {
case l: L[c,d] => l.f
}
def main(args: Array[String]) {
println {
test(new L[Int,Int](identity) with Node[Nothing]: Node[Int => String])(3): String
}
}
} [~ellbur], I think your example is interesting. Technically speaking, that's not at all the desugaring used: a typed match, that is However, it's true that pattern matching on sum types can usually be understood using elimination forms (your For Scala, I'd be happier with explicit witnesses of type equality, like in GHC's core language. GADT translation just inserts a checkcast after typechecking, but this typechecking produces no certificate that the type is right, unlike GHC does. IMHO, if GHC hackers feel the need to use such high-assurance technology, one cannot hope that Scalac magically gets this right. But getting this right will take no less than one PhD student, and right now I'm not sure there are the technical foundations to get this started. |
Owen Healy (ellbur) said:
Yes, very true. In fact, that's how I would intuitively read this GADT definition in the presence of To me, it is more surprising that that intuitive reading turns out not to hold. |
Arnold deVos (a4dev) said: object Test {
trait B
case class C[X, Y]( x: X, y: Y, f: X => Y) extends B
def eval(b: B) = b match { case C(x, y, f) => f(y) }
eval(C("abc", 0, (x: String) => x.length))
}
Test
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at Test$$anonfun$1.apply(<console>:13)
at Test$.eval(<console>:11)
... 45 elided |
@retronym said (edited on Apr 2, 2015 3:19:04 AM UTC): |
Arnold deVos (a4dev) said:
I see. |
(sorry, wrong issue) |
Fix unlikely in Scala 2 but see scala/scala3#3989 and scala/scala3#4013 for the Dotty plans. |
This might warrant fixing if anybody's interested — the main issue was deciding how to fix the bug. Backporting the fix to Scalac would help figuring out if there are major (and valid) uses for the old behavior. |
3.0.0:
|
The following code produces a
ClassCastException
at runtime:The text was updated successfully, but these errors were encountered: