diff options
author | Paul Phillips <paulp@improving.org> | 2012-02-11 13:16:06 -0800 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2012-02-11 23:05:22 -0800 |
commit | 7a6fa80937dec6c60efe53c915dfa3ba76b3af87 (patch) | |
tree | 76fbd019dfcb0caf284ba8f95bc2dfe962896506 /test/files/pos | |
parent | c478eb770ddf27de64d55426f0fdd3fd81d11f22 (diff) | |
download | scala-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')
-rw-r--r-- | test/files/pos/existentials-harmful.scala | 54 | ||||
-rw-r--r-- | test/files/pos/existentials.scala | 9 |
2 files changed, 63 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 + } + } +} diff --git a/test/files/pos/existentials.scala b/test/files/pos/existentials.scala new file mode 100644 index 0000000000..c51f60b546 --- /dev/null +++ b/test/files/pos/existentials.scala @@ -0,0 +1,9 @@ +class A { + def f() = { case class Bob(); Bob } + + val quux0 = f() + def quux1 = f() + + val bippy0 = f _ + def bippy1 = f _ +} |