-
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
Unsoundness bug in pattern matcher when pattern reveals existentials #6680
Comments
Imported From: https://issues.scala-lang.org/browse/SI-6680?orig=1 |
@retronym said: |
@adriaanm said (edited on Nov 17, 2012 10:17:34 PM UTC): trait Super[+A]
// `Hidden` must occur in both variance positions (covariant/contravariant) for the sneakiness to work
// this way type inference will infer Any for `Hidden` and `A` in the pattern below
case class Concrete[Hidden, +A](havoc: Hidden => Hidden) extends Super[A]
object Test extends App {
(Concrete((x: Int) => x): Super[Any]) match {
case Concrete(f) => f("not what you'd expect")
}
} |
@pchiusano said: |
@paulp said: case class Cell[A](var x: A)
object Test {
def f(x: Any) = x match { case y @ Cell(_) => y } // Inferred type is Cell[Any]
def g(x: Any) = x match { case y: Cell[_] => y } // This one infers Cell[_] as the other one should
def main(args: Array[String]): Unit = {
val x = new Cell(1)
val y = f(x)
y.x = "abc"
println(x.x + 1)
}
}
/***
% scala Test
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:105)
at Test$.main(a.scala:12)
at Test.main(a.scala)
***/ |
@paulp said: case class Concrete[A](havoc: A => A)
object Test extends App {
(Concrete((x: Int) => x): Any) match { case Concrete(f) => f("not what you'd expect") }
} |
Stephen Compall (s11001001) said: trait AO[A];case class AOA[A,B](f:A=>B,e:A=>A)extends AO[B]
def unsfeCoerce[A,B]=(AOA[B,B](a=>a,a=>a):AO[B])match{case AOA(id,_)=>id:(A=>B)} |
@paulp said: |
@paulp said: case class C[A](f:A=>A);def f(x:Any)=x match { case C(f)=>f("") };f(C[Int](x=>x)) |
@retronym said: This is only enabled under -Xstrict-inference as the unsoundness is widely exploited. I'll leave this ticket open to track that. But I'd be interested in Paul C. and Stephen's experiences with that flag. |
Stephen Compall (s11001001) said: I've found #7990 and #7991 in some initial experiments, though. I tried to build scalaz-seven core head against M7 with that option, and I believe #7991 would fix almost all of the resulting errors, if not all. I also imagine Paul C would prefer #7990 just be an error right out. |
Stephen Compall (s11001001) said: |
@adriaanm said: |
@retronym said: In the process I've spotted implementation issues with |
@paulp said: |
Stephen Compall (s11001001) said: |
"-Xstrict-inference was intended only as a coarse hacky start", says Paul at scala/bug#6680 (comment) GitHub search shows very few uses in the wild. My best is that a few people just enabled it because the name/description made it sound good/safer.
"-Xstrict-inference was intended only as a coarse hacky start", says Paul at scala/bug#6680 (comment) GitHub search shows very few uses in the wild. My best is that a few people just enabled it because the name/description made it sound good/safer.
Scala seems to refine all existential type variables to Any when pattern matching, which is unsound and can result in runtime errors. Here's an example data type:
Now take a look at an example usage which breaks. If I have a Stream[Int], and I match and obtain an Unfold(s, f), the type of (s,f) should be (S, S => Option[(A,S)]) forSome { type S }. But Scala just promotes everything to Any:
Notice that the type of s is Any. Likewise, the type of f is also wrong, it accepts an Any:
Since f expects Any, we can give it a String and get a runtime error:
I am using Scala 2.10.0-RC2, which, I understand has the new virtual pattern matcher turned on by default (I tried passing -Yvirtpatmat to the compiler but the option was not recognized.)
I find that this situation comes up a lot when writing libraries in Scala. It is extremely common to have a data type describing computations of some sort, and a separate interpreter which pattern matches to evaluate these computations for some semantics. The data type will frequently have existential type variables like this, and this bug means that the interpreter of the DSL is not typechecked!
Incidentally, the expression 'blah match { case Unfold(s,f) => f }' should trigger a type error due to an escaping skolem (rigid) type variable. Here's Haskell by comparison:
This yields:
The text was updated successfully, but these errors were encountered: