summaryrefslogtreecommitdiff
path: root/test/files/pos/existentials-harmful.scala
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-02-11 13:16:06 -0800
committerPaul Phillips <paulp@improving.org>2012-02-11 23:05:22 -0800
commit7a6fa80937dec6c60efe53c915dfa3ba76b3af87 (patch)
tree76fbd019dfcb0caf284ba8f95bc2dfe962896506 /test/files/pos/existentials-harmful.scala
parentc478eb770ddf27de64d55426f0fdd3fd81d11f22 (diff)
downloadscala-7a6fa80937dec6c60efe53c915dfa3ba76b3af87.tar.gz
scala-7a6fa80937dec6c60efe53c915dfa3ba76b3af87.tar.bz2
scala-7a6fa80937dec6c60efe53c915dfa3ba76b3af87.zip
Another existential problem down.
There is a window of danger when multiple related elements are being typed where something which is conceptually one thing can slip into two things, and those two things can be incompatible with one another. Less mysteriously, c478eb770d fixed this: def f = { object Bob ; Bob } ; val g = f But, it did not fix this: def f = { case class Bob() ; Bob } ; val g = f See test case pos/existentials-harmful.scala for an "in the wild" code example fixed by this commit. The root of the problem was that the getter and the field would each independently derive the same existential type to describe Bob, but those existentials were not the same as one another. This has been the most elusive bug I have ever fixed. I want to cry when I think of how much time I've put into it over the past half decade or so. Unfortunately the way the repl works it is particularly good at eliciting those grotesque found/required error messages and so I was never able to let the thing go. There is still a cosmetic issue (from the last commit really) where compound types wind up with repeated parents. Closes SI-1195, SI-1201.
Diffstat (limited to 'test/files/pos/existentials-harmful.scala')
-rw-r--r--test/files/pos/existentials-harmful.scala54
1 files changed, 54 insertions, 0 deletions
diff --git a/test/files/pos/existentials-harmful.scala b/test/files/pos/existentials-harmful.scala
new file mode 100644
index 0000000000..8722852e8a
--- /dev/null
+++ b/test/files/pos/existentials-harmful.scala
@@ -0,0 +1,54 @@
+// a.scala
+// Mon Jul 11 14:18:26 PDT 2011
+
+object ExistentialsConsideredHarmful {
+ class Animal(val name: String)
+ object Dog extends Animal("Dog")
+ object Sheep extends Animal("Sheep")
+
+ trait Tools[A] {
+ def shave(a: A): A
+ }
+ def tools[A](a: A): Tools[A] = null // dummy
+
+ case class TransportBox[A <: Animal](animal: A, tools: Tools[A]) {
+ def label: String = animal.name
+ }
+
+ // 1.
+ def carry[A <: Animal](box: TransportBox[A]): Unit = {
+ println(box.animal.name+" got carried away")
+ }
+
+ val aBox =
+ if (math.random < 0.5)
+ TransportBox(Dog, tools(Dog))
+ else
+ TransportBox(Sheep, tools(Sheep))
+
+ // 2.
+ //aBox.tools.shave(aBox.animal)
+
+ // Use pattern match to avoid opening the existential twice
+ aBox match {
+ case TransportBox(animal, tools) => tools.shave(animal)
+ }
+
+ abstract class BoxCarrier[R <: Animal](box: TransportBox[R]) {
+ def speed: Int
+
+ def talkToAnimal: Unit = println("The carrier says hello to"+box.animal.name)
+ }
+
+ // 3.
+ //val bc = new BoxCarrier(aBox) {
+
+ // Use pattern match to avoid opening the existential twice
+ // Type annotation on bc is required ... possible compiler bug?
+ // val bc : BoxCarrier[_ <: Animal] = aBox match {
+ val bc = aBox match {
+ case tb : TransportBox[a] => new BoxCarrier(tb) {
+ def speed: Int = 12
+ }
+ }
+}