This compiles:
import scala.collection._
trait Foo[A, +This <: SortedSet[A] with SortedSetLike[A,This]]
extends SortedSetLike[A, This] { this: This =>
def bar: This = (this: SortedSetLike[A,This]).empty
}
But if the upcast is removed it fails to compile:
import scala.collection._
trait Foo[A, +This <: SortedSet[A] with SortedSetLike[A,This]]
extends SortedSetLike[A, This] { this: This =>
def bar: This = this.empty
}
Why? From the extends
clause we know that Foo
is a SortedSetLike[A, This]
, so the upcast is valid of course - but doesn't this show that the compiler has allowed conflicting inheritance to occur?
The SortedSetLike trait inherits the empty method from SetLike.
/** The empty set of the same type as this set
* @return an empty set of type `This`.
*/
def empty: This
But SortedSet overrides the empty method and has an explicit return type:
/** Needs to be overridden in subclasses. */
override def empty: SortedSet[A] = SortedSet.empty[A]
Since you specify that This is a subclass of SortedSet the compiler will find SortedSet's implementation of empty first, which returns a SortedSet. The compiler does not know how to convert the resulting SortedSet to your This subclass.
But if you upcast to the SortedSetLike trait the compiler will find its empty method which returns a This.