Reputation: 2582
Why does this happily compile,
class Foo[T]
class DerivedFoo[T] extends Foo[T]
class Bar(val foo: Foo[_])
class DerivedBar(override val foo: DerivedFoo[_]) extends Bar(foo)
while this does not?
class OtherDerivedFoo[T, U] extends Foo[T]
class OtherDerivedBar(override val foo: OtherDerivedFoo[_, _]) extends Bar(foo)
//error: value foo overrides nothing
Is there a workaround? Thanks.
Upvotes: 3
Views: 850
Reputation: 14227
Seems this is a Scala compiler bug, Scala compiler will check whether subclass's override variable match the superclass's variable type, by checkOverride method,
For DerivedBar
& OtherDerivedBar
it's checking the Existential types
(thats the wildcard _
) whether matches with Bar.foo
type by matchesType, but for OtherDerivedBar
it has 2 ExistentialType, so it will fail on sameLength compare method, this will cause type mismatch.
As Andrey's solution, actually the compiler will compile OtherDerivedBar
to [ClassArgsType, ExistentialType]
, this will pass on the sameLength
compare, so no compile error will thrown.
but actually even OtherDerivedBar
has 2 ExistentialType
it also should be legal override type for Foo, since:
type F = OtherDerivedFoo[_, _]
class OtherDerivedBar(override val foo: F) extends Bar(foo)
it's also compiled.
Upvotes: 1
Reputation: 44937
Workaround:
Currently, I cannot quite articulate why it works, but it works:
import scala.language.existentials
class DerivedFoo2[T, U] extends Foo[T]
class DerivedBar2(
override val foo: (Foo[X] with DerivedFoo2[X, _]) forSome { type X }
) extends Bar(foo)
(I've replaced OtherDerivedFoo
by DerivedFoo2
, see renaming notice below)
Renaming
I have renamed the classes as follows, to emphasize the parallels between the two cases, and to make the code of the workaround shorter:
Assuming that you have
class Foo[T]
class Bar(val foo: Foo[_])
This compiles:
class DerivedFoo1[T] extends Foo[T]
class DerivedBar1(override val foo: DerivedFoo1[_]) extends Bar(foo)
But this doesn't:
class DerivedFoo2[T, U] extends Foo[T]
class DerivedBar2(override val foo: DerivedFoo2[_, _]) extends Bar(foo)
Upvotes: 2