The following piece of code does not compile :
trait A[F] {
def find(x: Int): F
def fill(f: F): Unit
}
object TestA {
def test[T <: A[F] forSome { type F }](t: T) =
t.fill(t.find(0))
}
It returns the following compilation error :
test.scala:8: error: type mismatch;
found : (some other)F(in type T)
required: F(in type T)
t.fill(t.find(0))
^
However the following code complies just fine :
trait B[F] {
type R = F
def find(x: Int): R
def fill(f: R): Unit
}
object TestB {
def test[T <: B[F] forSome { type F }](t: T) =
t.fill(t.find(0))
}
I have two questions here :
I expect the fist piece of code to compile. Why does it not?
If there is a good reason why first piece of code does not compile, I would expect the second to not compile either, for the same reason. How then, does it compile successfully?
Is either of these a bug?
I don't know why the compiler differentiates the two pieces of code. Basically, the code doesn't compile because the type returned by
find
and the type expected byfill
don't have to be the sameF
, at least iffind
andfill
were called on two different objects.You could make the first piece of code to compile with:
And you could make the second piece of code not to compile with:
This should be rather a comment than an answer, but I don't have 50 reputation yet.
To understand what's happening, let's look at simpler versions of
TestA.test
andTestB.test
.Notice how the type of the intermediate value
s
refers toString
, while the type of the intermediate valuer
does not.Once we throw in the existentials, we end up with an intermediate value
s
whose type is equivalent toAny
, and which thus isn't a valid input fora.fill
. The intermediate type forr
, however, is stillb.R
, and so it is still an appropriate input forb.fill
. The reason its type is stillb.R
is becauseb.R
doesn't refer toF
, and so according to the simplification rules for existential types,b.R forSome {type F}
is equivalent tob.R
, in the same way thatInt forSome {type F}
is equivalent toInt
.Well, there is certainly a bug somewhere (as of scalac 2.11.7), because the following does not type check.
So either I'm wrong to think that
b.R
does not refer toF
, in which caseb.R forSome {type F}
is not equivalent tob.R
and yourTestB.test
should not type check but it does, orb.R forSome {type F}
is equivalalent tob.R
, in which case myTestB.test3
should type check but it doesn't.I'm quite convinced that the bug is with the latter, because the error even occurs when the existential quantification has nothing to do with
b.R
, as in the following example.